首页 > 解决方案 > 为什么 Mockery 无法为我的模型创建别名

问题描述

我有以下模型:

namespace App\Model;

use Illuminate\Database\Eloquent\Model;

class MyModel extends Model
{
    public static function foo():bool
    {
      return true;
    }
}

为此,我制作了以下控制器:


namespace App\Controler;

use App\Model\Foo;

class MyController
{
   public function bar()
   {
      $value=MyModel::foo();
      if($value){
        return "OK"; 
      }
      throw new \Exception("Foo not true");
   }
}

我想测试我的控制器:

namespace Tests;

use Illuminate\Foundation\Testing\TestCase as BaseTestCase;
use App\Model\MyModel;
use Mockery;

class MyControllerTest extends BaseTestCase
{
   public function testBar()
   {
      $mock=Mockery::mock('alias:'.MyModel::class);
      $mock->shouldReceive('foo')->andReturn(false);
      /// Rest of thest here
   }
}

但是一旦我运行我的测试,我就会收到以下错误:

PHPUnit 7.5.20 by Sebastian Bergmann and contributors.

E                                                                   1 / 1 (100%)

Time: 1.62 seconds, Memory: 14.00 MB

There was 1 error:

1) Tests\MyControllerTest::testBar
Mockery\Exception\RuntimeException: Could not load mock App\Model\MyModel, class already exists

/var/www/html/vendor/mockery/mockery/library/Mockery/Container.php:226
/var/www/html/vendor/mockery/mockery/library/Mockery.php:118
/var/www/html/tests/MyControllerTest.php:20

ERRORS!
Tests: 1, Assertions: 0, Errors: 1.

为了减轻https://stackoverflow.com/a/53266979/4706711中看到的错误,我尝试了:

namespace Tests;

use Illuminate\Foundation\Testing\TestCase as BaseTestCase;
use App\Model\MyModel;
use Mockery;

class MyControllerTest extends BaseTestCase
{

  /**
   * @runInSeparateProcess 
   * @preserveGlobalState disabled
   */
   public function testBar()
   {
      $mock=Mockery::mock('alias:'.MyModel::class);
      $mock->shouldReceive('foo')->andReturn(false);
      /// Rest of thest here
   }
}

但我仍然得到同样的错误。

根据@mohammad.kaab 的回答,我尝试了以下方法:

namespace Tests;

use Illuminate\Foundation\Testing\TestCase as BaseTestCase;
use App\Model\MyModel;
use Mockery;

class MyControllerTest extends BaseTestCase
{

  /**
   * @runInSeparateProcess 
   * @preserveGlobalState disabled
   */
   public function testBar()
   {
      $this->app->instance(MyModel::class, \Mockery::mock(MyModel::class, function($mock){
            $mock->shouldReceive('foo')->andReturn(true);
        }));
        $myModel = $this->app->make(MyModel::class);
        dd($myModel::foo()); // should return true
   }
}

但是它不能工作,因为\Mockery::mock模拟一个实例并且不模拟类本身。因此我尝试了以下方法:

   public function testBar()
   {
      $mock=Mockery::mock('alias:'.MyModel::class);
      $mock->shouldReceive('foo')->andReturn(false);
      /// Rest of thest here
   }

并没有为我工作。

标签: phplaravelunit-testinglaravel-5.7mockery

解决方案


也许您可以使用此代码

$this->app->instance(MyModel::class, \Mockery::mock(MyModel::class, function($mock){
            $mock->shouldReceive('foo')->andReturn(true);
        }));
        $myModel = $this->app->make(MyModel::class);
        dd($myModel::foo()); // should return true

推荐阅读