自称 PhpUnit / Mockery 的模拟方法

Posted

技术标签:

【中文标题】自称 PhpUnit / Mockery 的模拟方法【英文标题】:Mock method that call it self PhpUnit / Mockery 【发布时间】:2014-08-24 13:23:05 【问题描述】:

大家好,我有一个方法,它可以在特定情况下调用它自己,该方法的一个简短示例可以是:

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);
    

但是我如何在代码上方编写 cmets,我无法正确模拟方法 add,因为我需要对其进行断言,但即使是这样,它也会再次被调用,我应该完成它的行为。

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

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

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

【问题讨论】:

【参考方案1】:

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

在某些情况下这条规则似乎不适用,但所有这些情况都表明你的班级做的事情太多,需要分成几部分,而你没有测试的所有部分都可以被模拟。

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

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

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 方法的任何参数都没有任何好处,则返回值始终为零,这可能与您的示例代码没有显示值的任何其他位置有关可以观察到代码执行所触发的变化。

【讨论】:

【参考方案2】:

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

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

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

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

【讨论】:

以上是关于自称 PhpUnit / Mockery 的模拟方法的主要内容,如果未能解决你的问题,请参考以下文章

在 Laravel 中使用 Mockery/phpUnit 时出错

用于 PHPunit 的 Laravel 5.4 模型模拟

在 Laravel 4 中使用 Mockery 模拟自定义类

Laravel 5 - 使用 Mockery 模拟 Eloquent 模型

PHPunit 和 Mockery:找不到方法

Mockery 无法使用 Eloquent 模型填充方法创建部分模拟