PHPUnit多次模拟不同方法

3

我是Unit test的新手,正在尝试使用PHPUnit框架。

我有一个调用两个其他函数的函数:

class Dummy{
    public function dummyFunction(){
        $this->anotherDummyFunction();
        .....
        $this->yetAnotherDummyFunction();
    }
    public function anotherDummyFunction(){

        .....

    }
    public function yetAnotherDummyFunction(){

        .....

    }
}

我希望在调用dummyFunction()时,这两个函数被调用。
这是测试类:
class TestDummyClass {
    public function testDummyFunction(){

        $dummyClassMock = $this->getMockBuilder('Dummy')
                     ->setMethods( array( 'anotherDummyFunction','yetAnotherDummyFunction' ) )
                     ->getMock();

        $dummyClassMock->expects($this->once())
             ->method( 'anotherDummyFunction' );

        $dummyClassMock->expects($this->once())
             ->method( 'yetAnotherDummyFunction' );

        $dummyClassMock->dummyFunction();
   }
}

现在我注意到,如果我以这种方式模拟Dummy类,结果是:

当调用1次时,期望方法名称等于anotherDummyFunction。该方法预计将被调用1次,实际上未被调用。

但是如果我以这种方式设置Mock对象

$dummyClassMock = $this->getMockBuilder('Dummy')
                     ->setMethods( array( 'anotherDummyFunction' ) )
                     ->getMock();

测试通过。最后,如果我使用setMethods(null)设置模拟对象,则测试再次失败。
看起来我可以传递只有一个元素的数组,检查是否调用了我想要检查的方法。但是我在这里看到过:https://jtreminio.com/2013/03/unit-testing-tutorial-part-5-mock-methods-and-overriding-constructors/ setMethods用于注入传递的方法的返回值,所以这不会对调用本身产生影响,除非我将dummyFunction放在setMethods中(在这种情况下,函数将返回null而不调用其他两个方法,这样测试就必须失败)。
我做错了什么吗?我已经看到了代码片段,其中setMethods()中有多个方法...为什么如果我在setMethods中放置两个方法,测试会失败?
谢谢

好的,这很奇怪,但对我起作用了。顺便问一下,你确定TestDummyClass是从PHPUnit_Framework_TestCase继承的吗?你使用的phpunit版本是什么?我的是4.6.9 - Alexander Guz
谢谢Alexander,是的,它继承自PHPUnit_Framework_TestCase,实际上其他测试都通过了。我正在使用Sublime Text和Sublime Text的PHPUnit插件进行工作。phpUnit的版本是4.6.6,但我认为我不能使用新版本,因为插件不支持。稍后我会尝试使用另一个编辑器和新版本的phpUnit。 - Manu
1个回答

3
你正在使用 $this->once(),这意味着只有在每个测试用例中调用该方法一次时,测试才能通过!
你可能需要的是 $this->any(),它不要求每次都调用该方法。

你是指“只有在每个测试用例中调用方法恰好一次,测试才能通过”的意思吗?也就是说,如果我有两个测试方法,该函数必须在其中一个测试方法中调用,否则测试将无法通过?如果我使用$this->any()进行测试,即使根本没有调用该方法,测试是否仍会通过?(0 次调用也通过?)我已经将模拟对象声明为方法变量,因此其他测试方法无法访问它。 - Manu
是的,如果您有两个名为test*的方法,则在使用$this->once()时,模拟方法必须在每个方法中恰好调用一次(不多也不少)。如果该方法根本没有被调用,则测试确实会通过。您确定这些方法实际上已经被“调用”了吗?如果您只在生产代码中的dummyFunction内部调用它们,则模拟的dummyFunction将不会调用它们。 - lxg
为什么它们不被模拟的dummyFunction调用?这是一个模拟,而不是存根...模拟将执行真实方法所做的事情...存根只返回null或者你设置的任何值。因此,如果真实方法调用其他两个方法,模拟将具有相同的行为,这些方法必须被调用,测试必须通过。 - Manu

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接