简体   繁体   English

如何使用PHPUnit测试一个方法调用同一个类的其他方法,但是没有返回值

[英]How to use PHPUnit to test a method that calls other methods of the same class, but returns no value

How do you write a unit test for a method that calls other methods of the same class, but doesn't return a value?如何为调用同一类的其他方法但不返回值的方法编写单元测试? (Let's say with PHPUnit.) (假设使用 PHPUnit。)

For example, let's say that I have the following class:例如,假设我有以下课程:

class MyClass {

    public function doEverything() {

        $this->doA();
        $this->doB();
        $this->doC();

    }

    public function doA() {
        // do something, return nothing
    }

    public function doB() {
        // do something, return nothing
    }

    public function doC() {
        // do something, return nothing
    }

}

How would you test doEverything() ?你将如何测试doEverything()

EDIT:编辑:

I'm asking this because from what I've read it seems like pretty much every method should have its own dedicated unit test.我问这个是因为从我读过的内容来看,几乎每种方法都应该有自己的专用单元测试。 Of course, you also have functional and integration tests, but those target specific routines, so to speak (not on a per method level necessarily).当然,您也有功能和集成测试,但可以这么说,这些测试针对特定的例程(不一定在每个方法级别上)。

But if pretty much every method needs its own unit test, I'm thinking it would be "best practice" to unit test all of the above methods.但是,如果几乎每种方法都需要自己的单元测试,我认为对上述所有方法进行单元测试是“最佳实践”。 Yes/no?是/否?

Okay!好的! I've figured it out!我已经想通了! As might be expected, mocking is what I need in this situation--and mocking a sibling method is called partial mocking .正如所料,嘲讽是什么,我需要在这种情况下-和嘲讽兄弟姐妹方法称为部分嘲讽 There's some pretty great info about PHPUnit mocking in this article by Juan Treminio .Juan Treminio 的这篇文章中,有一些关于 PHPUnit 模拟的非常好的信息。

So to test doEverything() in the above class, I would need to do something like this:所以要在上面的类中测试doEverything() ,我需要做这样的事情:

public function testDoEverything()
{

    // Any methods not specified in setMethods will execute perfectly normally,
    // and any methods that ARE specified return null (or whatever you specify)
    $mock = $this->getMockBuilder('\MyClass')
        ->setMethods(array('doA', 'doB', 'doC'))
        ->getMock();

    // doA() should be called once
    $mock->expects($this->once())
         ->method('doA');

    // doB() should be called once
    $mock->expects($this->once())
         ->method('doB');

    // doC() should be called once
    $mock->expects($this->once())
         ->method('doC');

    // Call doEverything and see if it calls the functions like our
    // above written expectations specify
    $mock->doEverything();
}

That's it!就是这样! Pretty easy!挺容易!

BONUS: If you use Laravel and Codeception...奖励:如果你使用 Laravel 和 Codeception ......

I'm using the Laravel Framework as well as Codeception, which made it a little bit trickier to figure out.我正在使用 Laravel 框架以及 Codeception,这使得弄清楚它有点棘手。 If you use Laravel and Codeception you'll need to do a little bit more to get it working, since the Laravel autoloading doesn't by default connect into the PHPUnit tests.如果您使用 Laravel 和 Codeception,您需要做更多工作才能使其正常工作,因为 Laravel 自动加载默认情况下不会连接到 PHPUnit 测试。 You'll basically need to update your unit.suite.yml to include Laravel4, as shown below:您基本上需要更新您的unit.suite.yml以包含 Laravel4,如下所示:

# Codeception Test Suite Configuration

# suite for unit (internal) tests.
class_name: UnitTester
modules:
    enabled: [Asserts, UnitHelper, Laravel4]

Once you've updated your file, don't forget to call php codecept.phar build to update your configuration.一旦你更新了你的文件,不要忘记调用php codecept.phar build来更新你的配置。

While your mocking test does achieve your goal, I would argue that you've decreased confidence in the code.虽然您的模拟测试确实实现了您的目标,但我认为您已经降低了对代码的信心。 Compare the original trivial method to the complicated method that tests it.将原始的琐碎方法与测试它的复杂方法进行比较。 The only way the method under test can fail is by forgetting to add one of the method calls or mistype a name.被测方法可能失败的唯一方法是忘记添加方法调用之一或错误输入名称。 But you're now doubly-likely to do that with all that additional code, and it doesn't have any tests!但是您现在很可能使用所有这些额外的代码来做到这一点,而且它没有任何测试!

Rule: If your test code is more complicated than the code under test, it needs its own tests.规则:如果您的测试代码比被测代码更复杂,则它需要自己的测试。

Given the above, you're better off finding another way to test the original code.鉴于上述情况,您最好找到另一种方法来测试原始代码。 For the method as written--three method calls with no parameters--inspection by eyeball is sufficient.对于所写的方法——三个没有参数的方法调用——用眼球检查就足够了。 But I suspect that the method does have some side-effects somewhere, otherwise you could delete it.但我怀疑该方法确实在某处有一些副作用,否则您可以将其删除。

Unit testing is about testing the class as a unit, not each method individually.单元测试是将类作为一个单元进行测试,而不是单独测试每个方法。 Testing each method alone is a good indication that you're writing your tests after the code.单独测试每种方法很好地表明您是在代码之后编写测试。 Employing Test Driven Development and writing your tests first will help you design a better class that is more-easily testable.采用测试驱动开发并首先编写测试将帮助您设计一个更易于测试的更好的类。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM