嘲笑模拟不返回指定值
Mockery mock not returning specified value
我在我的 Laravel 项目中使用 Mockery 来模拟用户 Eloquent 模型并测试路由。
这是我测试 /api/user/activate
路线的方式:
<?php
use Illuminate\Support\Facades\Session;
class ActivateTest extends TestCase
{
private $userMock;
public function setUp()
{
parent::setUp();
$this->userMock = Mockery::mock('App\User');
Session::start();
}
public function tearDown()
{
Mockery::close();
}
public function testActivate()
{
$this->userMock->shouldReceive('where->first')->once()->andReturn('test');
$this->userMock->shouldReceive('activate')->once();
$response = $this->call('POST', '/api/user/activate', [
'activationToken' => '838jfjnvu83u3',
'_token' => csrf_token()
]);
// This will be displayed in the PHPunit output
print_r($response->getContent());
$this->assertResponseStatus(200);
}
}
我遇到的问题是 andReturn('test')
似乎不起作用。 PHPunit 结果是:
F{"error":{"message":null,"statusCode":404}}
Time: 276 ms, Memory: 15.50Mb
There was 1 failure:
1) ActivateTest::testActivate
Failed asserting that 404 matches expected 200.
这是UserController
中activate()
的内容:
public function activate(Request $request)
{
$activation = $request->input();
$user = $this->user->where('activationToken', $activation['activationToken'])->first();
if(!$user) return $this->respondNotFound($user);
try
{
$user->activate($activation['password']);
}
catch(ModelException $e)
{
return $this->respondInternalError($e->errorMessages());
};
return $this->respondCreated('Account activated.');
}
问题是控制器中的 $user
是 null
,因为模拟没有返回 test
(在那种情况下,条件将评估为真,我不会得到404 响应)。
编辑:
我也尝试过使用 PHPunit 模拟,但没有成功:
$this->userMock = $this->getMockBuilder('App\User')->setMethods(['where', 'first', 'activate'])->getMock();
$this->userMock->expects($this->once())->method('where')->willReturn($this->userMock);
$this->userMock->expects($this->once())->method('first')->willReturn('test');
$this->userMock->expects($this->once())->method('activate');
仅仅模拟一个对象是不够的。您需要将该模拟对象注入到包含 activate()
函数的 class 中。
您也可以在 setUp()
函数中执行此操作。尝试添加这个...
$this->app->instance('App/User', $this->userMock);
当您想注入 App/User
的实例时,这将告诉 Laravel,以注入您刚刚创建的模拟对象。
问题是由 ->first()
引起的,因为它不是 Eloquent
或 User
classes 上不存在的方法。
为了解决这个问题,我创建了一个新的 UserRepository
并将其作为依赖项注入到控制器构造函数中。
class UserRepository implements UserRepositoryInterface
{
/**
* @var User
*/
protected $user;
/**
* @param User $user
*/
public function __construct(User $user)
{
$this->user = $user;
}
/**
* @param $activationToken
* @return mixed
*/
public function whereActivationToken($activationToken)
{
return $this->user->where('activationToken', $activationToken)->first();
}
}
在UserController
中注入:
public function __construct(UserRepository $userRepository)
{
$this->userRepository = $userRepository;
}
这就是测试 PostActivateTest
class 现在的样子:
use Illuminate\Support\Facades\Session;
class PostActivateTest extends TestCase
{
private $user;
private $userRepositoryMock;
public function setUp()
{
parent::setUp();
$this->user = Mockery::mock('App\User');
$this->userRepositoryMock = Mockery::mock('Repository\Database\UserRepository');
$this->app->instance('App\User', $this->user);
$this->app->instance('Bloom\BloomCRM\Repository\Database\UserRepository', $this->userRepositoryMock);
Session::start();
}
public function tearDown()
{
Mockery::close();
}
public function testActivate()
{
$this->userRepositoryMock->shouldReceive('whereActivationToken')->once()->andReturn($this->user);
$this->user->shouldReceive('activate')->once();
$this->call('POST', '/api/user/activate', [
'activationToken' => '838jfjnvu83u3',
'password' => 'test',
'_token' => csrf_token()
]);
$this->assertResponseStatus(201);
}
}
我在我的 Laravel 项目中使用 Mockery 来模拟用户 Eloquent 模型并测试路由。
这是我测试 /api/user/activate
路线的方式:
<?php
use Illuminate\Support\Facades\Session;
class ActivateTest extends TestCase
{
private $userMock;
public function setUp()
{
parent::setUp();
$this->userMock = Mockery::mock('App\User');
Session::start();
}
public function tearDown()
{
Mockery::close();
}
public function testActivate()
{
$this->userMock->shouldReceive('where->first')->once()->andReturn('test');
$this->userMock->shouldReceive('activate')->once();
$response = $this->call('POST', '/api/user/activate', [
'activationToken' => '838jfjnvu83u3',
'_token' => csrf_token()
]);
// This will be displayed in the PHPunit output
print_r($response->getContent());
$this->assertResponseStatus(200);
}
}
我遇到的问题是 andReturn('test')
似乎不起作用。 PHPunit 结果是:
F{"error":{"message":null,"statusCode":404}}
Time: 276 ms, Memory: 15.50Mb
There was 1 failure:
1) ActivateTest::testActivate
Failed asserting that 404 matches expected 200.
这是UserController
中activate()
的内容:
public function activate(Request $request)
{
$activation = $request->input();
$user = $this->user->where('activationToken', $activation['activationToken'])->first();
if(!$user) return $this->respondNotFound($user);
try
{
$user->activate($activation['password']);
}
catch(ModelException $e)
{
return $this->respondInternalError($e->errorMessages());
};
return $this->respondCreated('Account activated.');
}
问题是控制器中的 $user
是 null
,因为模拟没有返回 test
(在那种情况下,条件将评估为真,我不会得到404 响应)。
编辑:
我也尝试过使用 PHPunit 模拟,但没有成功:
$this->userMock = $this->getMockBuilder('App\User')->setMethods(['where', 'first', 'activate'])->getMock();
$this->userMock->expects($this->once())->method('where')->willReturn($this->userMock);
$this->userMock->expects($this->once())->method('first')->willReturn('test');
$this->userMock->expects($this->once())->method('activate');
仅仅模拟一个对象是不够的。您需要将该模拟对象注入到包含 activate()
函数的 class 中。
您也可以在 setUp()
函数中执行此操作。尝试添加这个...
$this->app->instance('App/User', $this->userMock);
当您想注入 App/User
的实例时,这将告诉 Laravel,以注入您刚刚创建的模拟对象。
问题是由 ->first()
引起的,因为它不是 Eloquent
或 User
classes 上不存在的方法。
为了解决这个问题,我创建了一个新的 UserRepository
并将其作为依赖项注入到控制器构造函数中。
class UserRepository implements UserRepositoryInterface
{
/**
* @var User
*/
protected $user;
/**
* @param User $user
*/
public function __construct(User $user)
{
$this->user = $user;
}
/**
* @param $activationToken
* @return mixed
*/
public function whereActivationToken($activationToken)
{
return $this->user->where('activationToken', $activationToken)->first();
}
}
在UserController
中注入:
public function __construct(UserRepository $userRepository)
{
$this->userRepository = $userRepository;
}
这就是测试 PostActivateTest
class 现在的样子:
use Illuminate\Support\Facades\Session;
class PostActivateTest extends TestCase
{
private $user;
private $userRepositoryMock;
public function setUp()
{
parent::setUp();
$this->user = Mockery::mock('App\User');
$this->userRepositoryMock = Mockery::mock('Repository\Database\UserRepository');
$this->app->instance('App\User', $this->user);
$this->app->instance('Bloom\BloomCRM\Repository\Database\UserRepository', $this->userRepositoryMock);
Session::start();
}
public function tearDown()
{
Mockery::close();
}
public function testActivate()
{
$this->userRepositoryMock->shouldReceive('whereActivationToken')->once()->andReturn($this->user);
$this->user->shouldReceive('activate')->once();
$this->call('POST', '/api/user/activate', [
'activationToken' => '838jfjnvu83u3',
'password' => 'test',
'_token' => csrf_token()
]);
$this->assertResponseStatus(201);
}
}