【问题标题】:How to PHPUnit test a method with no return value?如何 PHPUnit 测试没有返回值的方法?
【发布时间】:2015-02-15 04:12:12
【问题描述】:

我正在尝试测试我编写的以下类中的方法(函数比显示的要多,基本上,每个 is_*() 方法都有一个函数):

class Validate {
  private static $initialized = false;

  /**
  * Construct won't be called inside this class and is uncallable from the outside. This prevents
  * instantiating this class. This is by purpose, because we want a static class.
  */
  private function __construct() {}

  /**
  * If needed, allows the class to initialize itself
  */
  private static function initialize()
  {
    if(self::$initialized) {
      return;
    } else {
      self::$initialized = true;
      //Set any other class static variables here
    }
  }

  ...

  public static function isString($string) {
    self::initialize();
    if(!is_string($string)) throw new InvalidArgumentException('Expected a string but found ' . gettype($string));
  }

  ...

}

当我测试方法是否在无效输入上引发异常时,效果很好!但是,当我测试该方法是否按预期工作时,PHPUnit 会抱怨,因为我在测试中没有断言。具体错误是:

# RISKY This test did not perform any assertions

但是,我没有任何价值可以断言,所以我不确定如何克服这个问题。

我读过一些关于测试静态方法的文章,但这似乎主要涵盖了静态方法之间的依赖关系。此外,即使是非静态方法也可能没有返回值,那么,如何解决这个问题?

供参考,我的测试代码:

class ValidateTest extends PHPUnit_Framework_TestCase {
  /**
  * @covers ../data/objects/Validate::isString
  * @expectedException InvalidArgumentException
  */
  public function testIsStringThrowsExceptionArgumentInvalid() {
    Validate::isString(NULL);
  }

  /**
  * @covers ../data/objects/Validate::isString
  */
  public function testIsStringNoExceptionArgumentValid() {
    Validate::isString("I am a string.");
  }
}

【问题讨论】:

  • 为什么该方法不会返回真/假?为什么将非字符串值作为参数传递时会是一个例外,因为显然是一种测试某物是否为字符串的方法,应该期望非字符串值或者该方法没有实用程序。这似乎是一种考虑不周的方法。
  • @MikeBrant 它不会返回,因为它没有必要。我在我的代码中使用该方法作为中断/断言 - 如果该方法没有引发异常,我的代码将继续正常运行。如果是,则必须处理异常。根本没有理由从这些方法中返回任何内容,更没有理由编写 if/else 语句并花费周期检查这些返回值。我想要异常而不是 TRUE/FALSE,因为异常可以停止代码执行。如果在 Java(或大多数类型化的语言)中将一个 int 放在数组应该放在的位置,则会出现异常。我想要类似的功能。
  • @MikeBrant 此外,正确的测试意味着确保我的方法适用于无效和有效输入。
  • 是的,但是当你有这样的验证方法时,为什么验证类要向调用者规定行为呢?也许调用这个类的代码正试图根据值是否为字符串来决定要做的事情,完全期望有时可能存在其他数据类型。为什么这个验证类应该抛出一个必须处理的异常,而不是仅仅给调用者它正在寻找的东西——了解所讨论的值是否确实是字符串类型?这似乎也是一个微不足道的函数,因为 PHP 有这个内置函数。
  • @MikeBrant PHP 确实构建了它,is_string(),我在函数中使用它。但是,由于我确实使用异常,我不想到处为新的异常编写代码。拥有一个验证类并不少见。我理解你所说的课程是如何运作的,你有正确的观点。然而,你指出的方式不是我设计的方式,虽然我的设计总体上可能并不完美,但我认为它应该是我正在做的事情的方式。

标签: php unit-testing phpunit


【解决方案1】:

为防止出现有关断言的警告,您可以使用 @doesNotPerformAssertions 注释,如文档中所述:https://phpunit.de/manual/current/en/appendixes.annotations.html#idp1585440

或者,如果您更喜欢代码而不是注释: $this->doesNotPerformAssertions();

【讨论】:

  • 不错的答案,但是doesNotPerformAssertions 应该是expectNotToPerformAssertions,因为首先只返回当前值。 github
【解决方案2】:

assertNull测试void函数:

    /**
     * @covers ../data/objects/Validate::isString
     */
    public function testIsStringNoExceptionArgumentValid() {
         $this->assertNull( Validate::isString("I am a string.") );
    }

【讨论】:

  • 尝试使用 void 函数的返回值将(正确地)在许多 linter 中被标记。
【解决方案3】:

我遇到的一个解决方案是基于example 2.12 from chapter 2 of PHPUnit。对我来说感觉有点骇人听闻,但这是迄今为止我发现的最好的。此外,基于此PHPUnit Gitub issue discussion,似乎其他几个人想要此功能,但没有实施它的计划。

testIsStringNoExceptionArgumentValid() 更改为以下内容:

  /**
  * @covers ../data/objects/Validate::isString
  */
  public function testIsStringNoExceptionArgumentValid() {
    try {
      Validate::isString("I am a string.");
    } catch (InvalidArgumentException $notExpected) {
      $this->fail();
    }

    $this->assertTrue(TRUE);
  }

【讨论】:

  • 您不需要 try/catch 位。不需要fail(),异常会那样做。
  • 如何测试一个不返回任何内容且不抛出任何异常的方法
  • @Souad 要么让函数返回一些东西(你不需要在主程序逻辑中使用它!)或者创建一个本地变量,比如说“errorCode”,并且所有不按预期将 errorCode 增加 1,因此您可以 assertEquals(0,errorCode);
【解决方案4】:

如果你想测试一个 void 函数,你只需要在没有任何断言的情况下运行它。 如果有任何问题,它将引发异常并且测试将失败。无需输入 $this->assertTrue(TRUE);,因为您没有运行断言并且不需要断言来测试您的代码。

你会收到这样的消息


Time: 7.39 seconds, Memory: 16.00 MB

OK (1 test, 0 assertions)
Process finished with exit code 0

【讨论】:

    猜你喜欢
    • 2021-02-12
    • 2015-08-23
    • 2010-11-16
    • 1970-01-01
    • 2014-10-02
    • 2013-06-20
    • 2021-07-27
    • 2016-03-21
    • 2011-05-09
    相关资源
    最近更新 更多