簡體   English   中英

用於模擬由新類對象調用的方法的單元測試

[英]Unit test for mocking a method called by new class object

我正在為現有代碼編寫單元測試,就像這樣

class someClass {
    public function __construct() { ... }

    public function someFoo($var) {
        ...
        $var = "something";
        ...
        $model = new someClass();
        model->someOtherFoo($var);
    }

    public someOtherFoo($var){
         // some code which has to be mocked
    }
}

我應該如何模擬調用函數“ someOtherFoo ”,以便它不會在someOtherFoo執行“ some code ”?

class someClassTest {
   public function someFoo() {
      $fixture = $this->getMock('someClass ', array('someOtherFoo'));
      $var = "something";
      ....
      // How to mock the call to someOtherFoo() here
   }

}

是否可以模擬構造函數,以便它返回我自己構造的函數或變量?

謝謝

無論你在被測方法中有new XXX(...) ,你都注定要失敗。 將實例化提取到同一個類的新方法 - createSomeClass(...) 這允許您創建一個被測試類的部分模擬,它從new方法返回一個stubbed或mock值。

class someClass {
    public function someFoo($var) {
        $model = $this->createSomeClass();  // call method instead of using new
        model->someOtherFoo($var);
    }

    public function createSomeClass() {  // now you can mock this method in the test
        return new someClass();
    }

    public function someOtherFoo($var){
         // some code which has to be mocked
    }
}

在測試中,在您調用someFoo()的實例中模擬createSomeClass() ,並在從第一個模擬調用返回的實例中模擬someOtherFoo()

function testSomeFoo() {
    // mock someOtherFoo() to ensure it gets the correct value for $arg
    $created = $this->getMock('someClass', array('someOtherFoo'));
    $created->expects($this->once())
            ->method('someOtherFoo')
            ->with('foo');

    // mock createSomeClass() to return the mock above
    $creator = $this->getMock('someClass', array('createSomeClass'));
    $creator->expects($this->once())
            ->method('createSomeClass')
            ->will($this->returnValue($created));

    // call someFoo() with the correct $arg
    $creator->someFoo('foo');
}

請記住,因為實例正在創建同一個類的另一個實例,所以通常會涉及兩個實例。 如果它更清楚,你可以在這里使用相同的模擬實例。

function testSomeFoo() {
    $fixture = $this->getMock('someClass', array('createSomeClass', 'someOtherFoo'));

    // mock createSomeClass() to return the mock
    $fixture->expects($this->once())
            ->method('createSomeClass')
            ->will($this->returnValue($fixture));

    // mock someOtherFoo() to ensure it gets the correct value for $arg
    $fixture->expects($this->once())
            ->method('someOtherFoo')
            ->with('foo');

    // call someFoo() with the correct $arg
    $fixture->someFoo('foo');
}

您可以使用overload:模擬類名稱添加前綴overload:

查看關於Mocking Hard Dependencies的文檔。

你的例子是這樣的:

/**
 * @runTestsInSeparateProcesses
 * @preserveGlobalState disabled
 */
class SomeClassTest extends \PHPUnit\Framework\TestCase
{
    public function test_some_foo()
    {
        $someOtherClassMock = \Mockery::mock('overload:SomeOtherClass');
        $someOtherClassMock->shouldReceive('someOtherFoo')
            ->once()
            ->with('something')
            ->andReturn();

        $systemUnderTest = new SomeClass();

        $systemUnderTest->someFoo('something');
    }

}

我添加了@runTestsInSeparateProcesses注釋,因為通常@runTestsInSeparateProcesses的類也將用於其他測試。 如果沒有注釋,則自動加載器會因為class already exists錯誤而崩潰。

如果這是在測試套件中使用模擬類的唯一地方,那么您應該刪除注釋。

我在這里試圖通過白盒測試類__constructor來確保它自己調用一個類方法,並將一些數據傳入__constructor。

如果其他人出於同樣的原因在這里,我想我會分享我最終使用的方法(沒有在這個問題中使用的工廠風格的createSomeClass()方法)。

<?php
class someClass {

  public function __constructor($param1) {
    // here is the method in the constructor we want to call
    $this->someOtherFoo($param1);
  }

  public function someOtherFoo($var){  }

}

現在PHPUnit測試:

<?php
$paramData = 'someData';

// set up the mock class here
$model = $this->getMock('someClass', 
  array('someOtherFoo'), // override the method we want to check
  array($paramData) // we need to pass in a parameter to the __constructor
);

// test that someOtherFoo() is called once, with out test data
$model->expects($this->once())
      ->with($paramData)
      ->method('someOtherFoo');

// directly call the constructor, instead of doing "new someClass" like normal
$model->__construct($paramData);

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM