如何使用调用另一个方法的参数来模拟方法?

时间:2018-03-24 15:22:14

标签: php unit-testing mocking phpunit

我尝试为此类创建测试以测试getLanguageLabel()方法:

use Drupal\Core\Language\LanguageManagerInterface;
use Drupal\Core\Language\LanguageInterface;

class OnlyOne {

protected $languageManager;

  public function __construct(LanguageManagerInterface $language_manager) {
    $this->languageManager = $language_manager;
  }

  public function getLanguageLabel($language) {
    switch ($language) {
      case LanguageInterface::LANGCODE_NOT_SPECIFIED:
      case '':
        // If the language is empty then is Not specified.
        return $this->languageManager->getLanguage(LanguageInterface::LANGCODE_NOT_SPECIFIED)->getName();

      case LanguageInterface::LANGCODE_NOT_APPLICABLE:
        return $this->languageManager->getLanguage(LanguageInterface::LANGCODE_NOT_APPLICABLE)->getName();

      default:
        return ucfirst($language);
    }
  }

这是班级的测试:

  /**
   * @dataProvider providerGetLanguageLabel
   */
  public function testGetLanguageLabel($expected, $language_code) {
    // Language mock.
    $language = $this->createMock('Drupal\Core\Language\LanguageInterface');
    $language->expects($this->any())
      ->method('getName')
      ->willReturn($expected);

    // Language manager mock.
    $language_manager = $this->createMock('Drupal\Core\Language\LanguageManagerInterface');
    $language_manager->expects($this->any())
      ->method('getLanguage')
      ->with($language_code)
      ->willReturn($language);

    // Creating the object
    $only_one = new OnlyOne($language_manager);
    // Testing the function.
    $this->assertEquals($expected, $only_one->getLanguageLabel($language_code));
  }

  /**
   * Data provider for testGetLanguageLabel().
   */
  public function providerGetLanguageLabel() {
    $tests['empty langcode'] = ['Not specified', ''];
    // LanguageInterface::LANGCODE_NOT_SPECIFIED == 'und'
    $tests['und langcode'] = ['Not specified', LanguageInterface::LANGCODE_NOT_SPECIFIED];
    // LanguageInterface::LANGCODE_NOT_APPLICABLE == 'zxx'
    $tests['zxx langcode'] = ['Not applicable', LanguageInterface::LANGCODE_NOT_APPLICABLE];
    $tests['es langcode'] = ['Es', 'es'];
    $tests['en langcode'] = ['En', 'en'];

    return $tests;
  }

但似乎我正在以正确的方式模仿getLanguage()方法,因为我收到了这个错误:

There was 1 failure:

1) Drupal\Tests\onlyone\Unit\OnlyOneTest::testGetLanguageLabel with data set "empty langcode" ('Not specified', '')
Expectation failed for method name is equal to "getLanguage" when invoked zero or more times
Parameter 0 for invocation Drupal\Core\Language\LanguageManagerInterface::getLanguage('und') does not match expected value.
Failed asserting that two strings are equal.
--- Expected
+++ Actual
@@ @@
-''
+'und'

如何正确模拟getLanguage()方法?

1 个答案:

答案 0 :(得分:1)

您的测试并未反映生产代码的行为。

对于"空langcode"数据集,你希望用空刺激调用LanguageManager::getLanguage()。但是在生产代码中,如果OnlyOne::getLanguageLabel()传递空字符串,它会使用LANGCODE_NOT_SPECIFIED调用LanguageManager::getLanguage()。您可以在错误消息中看到这一点 - 它期待'',但它正在获得'und',评论中所说的是LANGCODE_NOT_SPECIFIED的值。

要使此测试有效,在传递OnlyOne::getLanguageLabel()时,您必须要求LanguageManager::getLanguage()的空字符串将传递LANGCODE_NOT_SPECIFIED。要使其与现有结构一起使用,您需要修改数据提供者 - 传递给getLanguageLabel()的值不一定与传递给getLanguage()的值相同。或者,由于这是一种特殊情况,您可以从数据提供者中删除此数据集,并将其作为自己的测试。