簡體   English   中英

PhpUnit:如何使用方法 arguments 的映射?

[英]PhpUnit: How can I use a mapping for method arguments?

我正在使用 PHPUnit 9.5 來測試我的代碼。 我的 class 看起來像這樣(簡化):

class MyClass {
  private $lib = null;

  public function __construct(?ExternalLib $lib = null) {
    $this->lib = $lib ?? new ExternalLib();
  }

  public function executeAB($value) {
    $this->lib->init();
    $this->lib->setOption(ExternalLib::OPTION_A, 'x');
    $this->lib->setOption(ExternalLib::OPTION_B, $value);
    // ... even more options which I don't need to test
    $this->lib->execute();
  }

  public function executeA() {
    $this->lib->init();
    $this->lib->setOption(ExternalLib::OPTION_A, 'y');
    $this->lib->execute();
  }

  public function executeB($value) {
    $this->lib->init();
    $this->lib->setOption(ExternalLib::OPTION_B, $value);
    $this->lib->execute();
  }
}

現在我想檢查在調用execute方法時是否設置了帶有值的給定選項。 我無權修改“ExternalLib”,但我可以使用測試替身。 我的問題是我想一起檢查選項鍵和值,因為它們依賴於它。 PHPUnit 只支持withwithConsecutive方法,不支持withMappingwithCallback方法。 我不想使用withConsecutive ,因為設置選項的順序無關緊要,而且這些方法中還有更多選項,我基本上不需要在此上下文中進行測試。

我認為有多種選擇可以解決這個問題,但似乎沒有一個是最優的。

a) 我可以使用withConsecutive ,但是當我只需要測試 1 或 2 時,我將不得不檢查 7 個以上的選項。此外,如果我更改選項在我的基礎 class 中設置的順序,測試將失敗。

b) 嘗試收集全局數組中的選項並在執行后驗證選項數組

public function testExecuteAB() {
  $libMock = $this->getMockBuilder(ExternalLib::class)->disableOriginalConstructor()->getMock();

  $options = [];
  $libMock->expects($this->once())->method('execute');
  $libMock->method('setOption')
    ->with(self::callback(function ($option, $value) use ($options) {
      $options[$option] = $value;
    }));

  $object = new MyClass($libMock);
  $object->executeAB('myValue');
  $this->assertSame('x', $options[ExternalLib::OPTION_A]);
  $this->assertSame('myValue', $options[ExternalLib::OPTION_B]);
}

c) 使用回調並實現映射。 所以我最近的嘗試是下面的代碼。 在這里我會得到一個參數不匹配錯誤,因為“with”只用一個參數(self::callback)被調用。

public function testExecuteAB() {
  $libMock = $this->getMockBuilder(ExternalLib::class)->disableOriginalConstructor()->getMock();

  $libMock->expects($this->once())->method('execute');
  $libMock->method('setOption')
    ->with(self::callback(function ($option, $value) {
      if ($option === ExternalLib::OPTION_A) {self::assertSame('x', $value);}
      if ($option === ExternalLib::OPTION_B) {self::assertSame('myValue', $value);}
    }));

  $object = new MyClass($libMock);
  $object->executeAB('myValue');
}

我在https://phpunit.readthedocs.io/en/9.5/test-doubles.html#test-doubles-mock-objects-examples-subjecttest3-php閱讀了文檔,但找不到解決我的問題的方法。 有人有想法驗證是否設置了給定的選項嗎?

在 PHPUnit 中還有willReturnCallback() ,其示例可以在本文底部看到。 使用此方法,您將獲得傳遞給模擬方法的所有 arguments,然后對它們運行斷言,並將返回值基於這些(如果需要)。

這樣,您將以下代碼放在一起解決了您的問題。 原則是,當您進行每次調用時,您可以根據定義的預期數組驗證預期參數......

$libMock->method('setOption')
    ->willReturnCallback(function ($option, $value) use ($expectations) 
         { 
             if (isset($expectations[$option])) { 
                 $this->assertSame($expectations[$option], $value);
             } 
         });

此外,根據是否涵蓋所有期望,您可以添加一個斷言,如果isset()失敗,該斷言將拋出。

暫無
暫無

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

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