Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/php/281.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Php Laravel 5-使用模拟来模拟雄辩的模型_Php_Unit Testing_Laravel_Eloquent_Mockery - Fatal编程技术网

Php Laravel 5-使用模拟来模拟雄辩的模型

Php Laravel 5-使用模拟来模拟雄辩的模型,php,unit-testing,laravel,eloquent,mockery,Php,Unit Testing,Laravel,Eloquent,Mockery,我在网上到处找,但似乎找不到我问题的答案。我一直在潜心使用PHPUnit和mockry测试Laravel中的控制器。然而,我似乎并没有正确地嘲笑我雄辩的模型。我确实以同样的方式模拟了我的Auth::user(),尽管在下面的测试中没有使用它 AddressController中需要测试的功能: public function edit($id) { $user = Auth::user(); $company = Company::where('kvk', $user->k

我在网上到处找,但似乎找不到我问题的答案。我一直在潜心使用PHPUnit和mockry测试Laravel中的控制器。然而,我似乎并没有正确地嘲笑我雄辩的模型。我确实以同样的方式模拟了我的Auth::user(),尽管在下面的测试中没有使用它

AddressController中需要测试的功能:

public function edit($id)
{
    $user = Auth::user();
    $company = Company::where('kvk', $user->kvk)->first();
    $address = Address::whereId($id)->first();

    if(is_null($address)) {
        return abort(404);
    }

    return view('pages.address.update')
        ->with(compact('address'));
}
包含设置和模拟方法的ControllerTest

abstract class ControllerTest extends TestCase
{
    /**
     * @var \App\Http\Controllers\Controller
     */
    protected $_controller;

    public function setUp(){
        parent::setUp();
        $this->createApplication();
    }

    public function tearDown()
    {
        parent::tearDown();
        Mockery::close();
    }

    protected function mock($class)
    {
        $mock = Mockery::mock($class);
        $this->app->instance($class, $mock);
        return $mock;
    }
}
AddressControllerTest扩展ControllerTest

class AddressControllerTest extends ControllerTest
{
    /**
     * @var \App\Models\Address
     */
    private $_address;

    /**
     * @var \App\Http\Controllers\AddressController
     */
    protected $_controller;

    public function setUp(){
        parent::setUp();
        $this->_controller = new AddressController();
        $this->_address = factory(Address::class)->make();
    }

    public function testEdit404(){
        $companyMock = $this->mock(Company::class);
        $companyMock
            ->shouldReceive('where')
            ->with('kvk', Mockery::any())
            ->once();
            ->andReturn(factory(Company::class)->make([
                'address_id' => $this->_address->id
            ]));

        $addressMock = $this->mock(Address::class);
        $addressMock
            ->shouldReceive('whereId')
            ->with($this->_address->id)
            ->once();
            ->andReturn(null);

        //First try to go to route with non existing address
        $this->action('GET', 'AddressController@edit', ['id' => $this->_address->id]);
        $this->assertResponseStatus(404);
    }
}
它不断抛出的错误是:

1) AddressControllerTest::testEdit404
Mockery\Exception\InvalidCountException: Method where("kvk", object(Mockery\Matcher\Any)) from Mockery_1_Genta_Models_Company should be called exactly 1 times but called 0 times.

也许有人有什么想法?

好吧,在找到Jeffrey Way(Laracasts背后的人)的多篇帖子后,他建议人们停止模仿有说服力的对象,而是使用内存数据库,我尝试了这种方法。我认为这可能对将来有同样问题的其他用户非常有用,所以我将在下面解释

现在,我已经使用sqlite编辑了我的'config/database.php'文件,以支持内存中的数据库选项:

'sqlite' => [
            'driver'   => 'sqlite',
            'database' => ':memory:',
            'prefix'   => '',
        ],
接下来,在文件顶部,您将看到以下配置:

'default' => env('DB_CONNECTION', 'mysql'),
这可以保持不变,这意味着Laravel将检查您的.env变量以找到“DB_连接”,或者使用mysql作为默认值。这可能是您在正常运行应用程序时希望执行的操作。但是,在进行测试时,您希望覆盖此配置,并将数据库配置临时设置为“sqlite”。这可以通过将“DB_CONNECTION”变量添加到.env文件中来实现:

DB_CONNECTION=mysql 
最后,在您的phpunit.xml(Laravel用于实例化单元测试的配置文件)中,您必须告诉您,在测试此变量时,应将其设置为“sqlite”:

<env name="DB_CONNECTION" value="sqlite"/> 
它会告诉Laravel在开始测试之前运行数据库迁移,这样您就可以像平常一样使用这些表


这样对我来说非常合适!希望你们能使用它。

在检查我的控制器方法是否被调用以及替换后是否被调用时,将$this->call()方法替换为$this->action()方法。但是问题仍然存在。对我来说很好。谢谢我还在迁移后为DB设置种子。需要注意的是:您会发现
@dependens testCreateCard
表示法无法将Id从一个方法传递到另一个方法,因为
setUp()
在每个测试中运行一次,每次都会重置DB。我用硬编码的值解决了这个问题。
use \Illuminate\Foundation\Testing\DatabaseMigrations;