Phpunit,如何测试方法是否"无"?

Joh*_*ith 20 php phpunit

class Testme()
{
    public function testMe ($a)
    {
        if ($a == 1)
        {
            throw new Exception ('YAY');
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

所以它很容易测试,如果它抛出异常

/**
 * @expectedException Exception
 */
public function test()
{
    new Testme(1);
}
Run Code Online (Sandbox Code Playgroud)

但如果什么都没做呢?

public function test()
{
    new Testme(2);
 ?? ? ? ? ?
}
Run Code Online (Sandbox Code Playgroud)

Xav*_*ero 14

方案

对于函数什么都不做,您有两种可能的方案:

场景1:没有退货声明

您的函数不执行任何操作,因为您不在其中执行操作,并且您不在其中包含return关键字:

public function doNothing()
{
    // Do nothing.
}
Run Code Online (Sandbox Code Playgroud)

场景2:使用return语句

你的函数什么都不做,因为你不执行它的行动和你做包括return在它的关键字没有表达任何返回值:

public function doNothing()
{
    // Do nothing.
    return;
}
Run Code Online (Sandbox Code Playgroud)

其他场景

我将不再处理以下情况:

  1. 除了执行可以在其他对象上测试的重要操作之外,您不返回任何内容的情况.在这种情况下,您必须对修改对象的结果状态进行单元测试.

  2. 除了返回某些内容之外什么都不做的情况,那么你应该对返回值进行单元测试.

浏览PHP手册中的文档

对于第一种情况,PHP手册记录了函数的计算表达式null.它在这里说:http://php.net/manual/en/functions.returning-values.php在一个注释中:

如果省略返回,则返回值NULL.

对于第二种情况,PHP手册记录了funcion的计算表达式null.它在这里说:http://php.net/manual/en/function.return.php在一个注释中:

如果未提供参数,则必须省略括号并返回NULL.[...]

结论

因此,清楚地记载了"无所事事"的功能必须进行评估null.

如何测试什么都不做的功能

只是断言你的期望:

$this->assertNull( $sut->doNothing() );
Run Code Online (Sandbox Code Playgroud)

通过这种方式,你可以"运用"你的功能,你可以使用它来使代码覆盖完成所有的行,并且通过测试null其评估值作为表达式来"预期""没有发生" ,如文档所述.

如何测试什么都不做的构造函数

不过要测试一个构造函数......好吧......常识:构造函数的目的是什么?创建某种类型的类吧?

所以...我更喜欢通过检查$sut已经创建的单元测试来启动100%的单元测试.这是我在做新课时所做的第一次测试.这是我在课程存在之前编写的测试.最后,这就是构造函数的用途.红酒吧.然后我创建了这个类.绿色酒吧.

假设我有一个Email带字符串的类,只有在传递有效的电子邮件时才会创建,否则抛出异常.这与你的问题非常相似.一种构造函数,只是"允许创建"或"通过爆炸系统来否认它".

我通常会这样做:

//-------------------------------------------------//
// Tests                                           //
//-------------------------------------------------//

/** @dataProvider validEmailProvider **/
public function testCreationIsOfProperClass( string $email )
{
    $sut = $this->getSut( $validEmail );
    $this->assertInstanceOf( Email::class, $sut );
}

/** @dataProvider invalidEmailProvider **/
public function testCreationThrowsExceptionIfEmailIsInvalid( string $invalidEmail )
{
    $this->expectException( EmailException::class );
    $this->getSut( $invalidEmail );
}

//-------------------------------------------------//
// Data providers                                  //
//-------------------------------------------------//

public function validEmailProvider() : array
{
    return
    [
        [ 'alice@example.com' ],
        [ 'bob.with-several+symbols@subdomain.another.subdomain.example.verylongTLD' ],
    ]
}

public function invalidEmailProvider() : array
{
    return
    [
        [ 'missing_at_symbol' ],
        [ 'charlie@cannotBeOnlyTld' ],
    ]
}

//-------------------------------------------------//
// Sut creators                                    //
//-------------------------------------------------//

private function getSut( string $email ) : Email
{
    return new Email( $email );
}
Run Code Online (Sandbox Code Playgroud)

当我使用PHP 7.0并且我将类型放在任何地方时,无论是输入参数还是返回类型,如果创建的对象不是电子邮件,则getSut()函数将首先失败.

但即使我写了省略返回类型,测试也会测试它预期会发生什么:new Email( 'valid@example.com' );它本身就是一个表达式,它应该评估为类的"某事" Email::class.

如何测试执行某些操作的构造函数

代码味道.构造函数可能不应该工作.如果有的话,只需存储参数.如果构造函数"工作"而不是存储参数,则考虑在getter上进行延迟处理,或者在工厂中委派该工作.

如何测试"除了存储参数之外什么都不做"的构造函数

就像之前一样+然后获取数据.

  1. 在第一次测试中测试创建是某事物的实例.
  2. 然后在另一个不同的测试中,运行类似getter的东西,它可以获得在构造函数中输入的内容,即使构造函数没有任何内容(除了存储它).

希望这会有所帮助.

  • 它确实有效,但请注意,如果该方法使用 PHP 7.1“void”返回类型,它仍然有效,但会被许多静态分析工具报告为“使用了 void 方法结果”。 (2认同)

Nic*_*rth 12

在 PHPUnit 7.2+ 中,您还可以使用 TestCase::expectNotToPerformAssertions()

public function test()
{
    // ...

    $this->expectNotToPerformAssertions();
}
Run Code Online (Sandbox Code Playgroud)

这与@doesNotPerformAssertions注释具有相同的行为。


Tom*_*uba 8

2018+

如今,最佳实践是针对这些情况进行注释:

/**
 * @doesNotPerformAssertions
 */
public function testSomething()
{
    $someService = new SomeObject();
    $someService->shallNotFail();
}
Run Code Online (Sandbox Code Playgroud)

  • 那里的文档**没有**声明此注释是“用于测试方法不执行任何操作”,**而是**为了避免警告消息,这始终是一个不好的做法。从字面上看,它说“@doesNotPerformAssertions 防止不执行断言的测试被认为是有风险的。”。这个问题**不是**问“如何在不测试任何内容的情况下执行代码”**而是**“如何测试它什么都不做”,这是不同的。使报告“沉默”只能暂时用于在我们有半编码的内容时禁用冗长的内容,而不是作为最终的行为。 (3认同)

Bre*_*ejk 3

这是不可能的。添加return语句并断言结果。

class Testme()
{
    public function testMe ($a)
    {
        if ($a == 1)
        {
            throw new Exception ('YAY');
        }

        return true;
    }
}
Run Code Online (Sandbox Code Playgroud)

进而

$object = new Testme();
$this->assertTrue($object->testMe(2));
Run Code Online (Sandbox Code Playgroud)