称之为自我PhpUnit / Mockery的模拟方法

时间:2014-07-03 12:11:02

标签: unit-testing phpunit mockery

大家好我有一个方法给出一个确定的情况,它称之为自我,该方法的一个简短例子可以是:

class MyClass
{

   protected $quantity;

   public function add($quantity)
   {
       for($i = 0; $i < $quantity; $i++)
       {
           $newQuantity = $quantity - 1;

           $this->setQuantity($newQuantity);

           $this->add($this->quantity);
       }

       return $this->quantity;
   }

   public function setQuantity($quantity)
   {
        $this->quantity = $quantity;
   }
}

如果我想为这个丑陋的方法编写一个测试(仅仅是为了举例),我会这样做:

<?php

use Mockery as m;

class TestMyClass
{

    public function teardown()
    {
       m::close();
    }

    public function test_add_method()
    {
        // Here come the problem because I need to mock that the method
        // will be called, but if I mock it, I cannot call it for an
        // assertion
        $mockMyClass = m::mock('MyClass[setQuantity,add]');

        $mockClass->shouldReceive('setQuantity')
                  ->once()
                  ->with(1)
                  ->andReturn(null);

        $result = $mockMyClass->add(1); // Here the problem

        $this->assertEquals(0,$result);
    }
}

但是我如何编写代码上面的注释,我无法正确地模拟方法add因为我需要对它做一个断言,但是甚至是真的会再次调用我应该完成的行为它。

错误跟踪运行此单元测试:

  

方法Mockery_1_Mocks_My_Class :: add()在此模拟上不存在   对象

你如何实现这个小功能的测试?

2 个答案:

答案 0 :(得分:3)

基本的经验法则:你不要嘲笑你要测试的课程,期间。

可能存在这样的规则似乎不适用的情况,但是所有这些情况都表明你的班级做了太多事情,需要分成几部分,然后你所测试的所有部分都可以被嘲笑。 / p>

现在你似乎试图模仿一些东西,因为你想测试内部递归调用。唐&#39;吨。因为它与外界无关,如何实现结果,无论是递归还是迭代。您总是可以将递归代码转换为交互式代码,反之亦然,唯一的区别是一种方法通常更适合该问题。

所以从本质上说你想做这样的事情:

public function test_add_one()
{
    $myClass = new MyClass();

    $result = $myClass->add(1); 

    $this->assertEquals(0,$result);
}

public function test_add_two()
{
    $myClass = new MyClass();

    $result = $myClass->add(2); 

    $this->assertEquals(0,$result); // I totally made this one up, haven't checked the code in detail
}

如果测试函数看起来像这样,并且您没有看到任何有益测试,无论您传递给add方法的参数是什么,返回值始终为零,这可能与您的示例代码无关,而不显示任何其他位置的值可以观察到代码执行触发的更改。

答案 1 :(得分:1)

嗯......你不需要这样做。

你的班级应该有getQuantity()。只需运行add(),然后对getQuantity()进行断言。

无论如何......你可以模拟setQuantity()(例如)抛出异常。 然后断言add将抛出异常。

也许您可以使用add(2)进行测试,仅针对特定参数模拟add:)