首页 > 解决方案 > 如何模拟 Laravel 模型以进行课程测试?

问题描述

我有这样的课:

<?php 
use App\Models\Product;

class ProductSearcher
{
    public function getPrintedProducts( $releasedOnly = true ) {
        $products = Product::with('productVersion','productVersion.tag')
                      ->where('printed', 1);
        if ($releasedOnly)
            $products->where('released', 1);
        $products = $products->get();
        return $products;
    }
}

在我的测试中,我写

// ... some other testing ...
public function testChossingCorrectingProductFromProductVersionIds()
{
    $productSearcher= new ProductSearcher;

    $productMock = \Mockery::mock( 'App\Models\Product' );
    $productMock->shouldReceive( 'with->where->where->get' )->andReturn( [] );

    $this->assertEmpty( $productSearcher->getPrintedProducts( true ) );
}
// ... some other testing ...

我运行测试但得到:

PHP Fatal error:  Cannot redeclare Mockery_1_App_Models_Product::mockery_init()

请问我做错了什么?或者测试这个功能的正确方法是什么?(这是一个单元测试,不应该太重,所以连接到测试数据库不是一个选项)

标签: phplaraveltestingmockingphpunit

解决方案


imo 测试这种功能的最佳方法是在内存中设置一个测试数据库。然后,当它为空时,在测试期间使用工厂创建几个模型。然后你就知道你有多少数据库记录以及什么样的记录。然后只需检查类是否返回正确的。

第二种方法是使用 IoC - 重构 ProductSearcher 并将 Product 模型类作为依赖项传递。然后,您可以在测试期间轻松模拟课程。

但我还有另一个问题 - 为什么你首先创建 ProductSearcher 类?使用范围会不会更容易?

如果您想使用工厂,请执行以下操作:

  • 首先 - 定义工厂。如果需要,用于主模型及其关系。为方便起见,您可以使用状态在记录中创建预定义的值集。https://laravel.com/docs/8.x/database-testing#defining-model-factories

  • 第二 - 创建一个测试。我的例子:

      public function testChossingCorrectingProductFromProductVersionIds()  
     {  
      $productSearcher= new ProductSearcher(); 
    
      $notPrinted = Product::factory->count(2)->create([  
          'printed' => false,  
          'released' => false  
      ]);  
    
      $printed = Product::factory->count(3)->create([  
          'printed' => true,  
          'released' => false  
      ]);   
    
      $releasedNotPrinted = Product::factory->count(4)->create([  
          'printed' => false,  
          'released' => true  
      ]);
    
      $releasedPrinted = Product::factory->count(5)->create([  
          'printed' => true,  
          'released' => true  
      ]);  
    
      $this->assertCount(8, $productSearcher->getPrintedProducts( false ) );  
      $this->assertCount(5, $productSearcher->getPrintedProducts( true ));  
    

    }

一些开发人员对“一个测试,一个断言”过于敏感,但我不是其中之一,如您所见:D


推荐阅读