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

Posted

技术标签:

【中文标题】在 Laravel 4 中使用 Mockery 模拟自定义类【英文标题】:Mocking a custom class with Mockery in Laravel 4 【发布时间】:2014-12-04 17:02:02 【问题描述】:

使用 Laravel 4.2,我在 /app/libraries 中有一个自定义类 TestyClass

使用 Mockery 和 phpUnit,我试图模拟这个类,但我的 Mock 似乎没有注册。

当我运行测试时,我得到Mockery\Exception\InvalidCountException: Method testymethod() from Mockery_0_TestyClass should be called exactly 1 times but called 0 times.

我正在测试的控制器运行 TestyClass::testymethod();testymethod() 内部的 Log::info 运行正常。

在 Laravel 4.2 中注册自定义类的 Mock 缺少什么?

$mock = Mockery::mock('TestyClass');
$mock->shouldReceive('testymethod')->once();

TestyClass:

class TestyClass 
    public static function testymethod() 
        Log::info('----=-=-=-=--=in heyhey!@!!=-=-=-=-=-=-=-12312312312312341');
        return true;
       

【问题讨论】:

【参考方案1】:

这段代码:

$mock = Mockery::mock('TestyClass');

创建一个扩展TestyClass的新类,添加模拟等所需的行为,然后创建它的实例并返回它,因此$mock是Mockery_0_TestyClass的实例

然后你告诉 mocky 你希望 instance 收到对 testymethod 的调用,但实际上你是在对 TestyClass 类方法进行静态调用。您可以通过嘲弄来做到这一点,但这不是很好,我不建议您这样做,您可能希望在进程隔离的情况下运行测试。

$mock = Mockery::mock('alias:TestyClass');

【讨论】:

是的,就像你说的不是很好,alias 为我的虚拟 TestyClass 工作,但当应用于我真实而广泛的 Lib 类时,它坏了:PHP Fatal error: Call to a member function __call() on a non-object in /Users/lukeshaheen/Dropbox/WWW/Phone2Action 2.0/vendor/mockery/mockery/library/Mockery/Loader/EvalLoader.php(16) : eval()'d code on line 633【参考方案2】:

你在打电话给你的控制器吗? 测试类方法和测试控制器是有区别的。 如果您正在测试控制器,请尝试使用$this->call - 示例;

class TestyClassTest extends TestCase 

  public function setUp()
  
    $this->mock = $this->mock('TestyClass');
  

  /* Move method to TestCase.php */
  public function mock($class)
  
    $mock = Mockery::mock($class);
    $this->app->instance($class, $mock);
    return $mock;
  

  /* Move method to TestCase.php */
  public function tearDown()
  
    Mockery::close();
  

  public function testIfTestyControllerRunsTestyMethodAndReturnsOk()
  
    // Step 3. Arrange
    // Last we arrange our test

    $this->mock->shouldReceive('testymethod')->once();

    // Step 2. Act
    // Then we write how we the results will be asserted.
    // The route should correspond with the controller executing the class method.
    // Eg. TestyMethodController@test; return $this->class->testymethod()

    **$this->call('GET', 'TestyController@test');**

    // Step 1. Assert
    // Start by writing the results we expect;
    // If the controller issues no Exceptions we should get a response header status 200.

    $this->assertResponseOk();
  

本质上 $mock->shouldReceive 是在模拟对象上设置一个侦听器,它正在等待方法运行 - 如果它运行则一切正常,否则你会得到一个 InvalidCountException。

希望对您有所帮助,祝您有美好的一天。

【讨论】:

【参考方案3】:

我遇到过类似的问题:无法识别课程。尝试使用 __construct 方法对其进行初始化。这对我有用。 (在 setUp 方法中设置它不起作用)。

public function __construct()

    $this->mock = Mockery::mock('TestyClass');

然后只调用测试方法:

$this->mock->shouldReceive('testymethod')->once();

【讨论】:

以上是关于在 Laravel 4 中使用 Mockery 模拟自定义类的主要内容,如果未能解决你的问题,请参考以下文章

使用 Mockery Eloquent 模型模拟 Laravel

Laravel 5 - 使用 Mockery 模拟 Eloquent 模型

Laravel Mockery:模拟返回逻辑

在 Laravel 中使用 Mockery/phpUnit 时出错

使用 Laravel 和 Mockery

如何使 Mockery 重载选项在 Laravel 5 上正常工作