【发布时间】:2014-09-14 17:36:39
【问题描述】:
我正在使用 laravel (4.2) 框架来开发 Web 应用程序 (PHP 5.4.25)。我创建了一个使用 eloquent-repository 实现的存储库接口,我在 UserController 中使用该存储库:
# app/controllers/UsersController.php
use Gas\Storage\User\UserRepositoryInterface as User;
class UsersController extends \BaseController {
protected $user;
public function __construct(User $user) {
$this->user = $user;
}
public function store() {
$input = Input::all();
$validator = Validator::make(Input::all(), $this->user->getRoles());
if ( $validator->passes() ) {
$this->user->getUser()->username = Input::get('username');
$this->user->getUser()->password = Hash::make(Input::get('password'));
$this->user->getUser()->first_name = Input::get('first_name');
$this->user->getUser()->last_name = Input::get('last_name');
$this->user->getUser()->email = Input::get('email');
$this->user->save();
return false;
} else {
return true;
}
}
}
我的存储库实现:
namespace Gas\Storage\User;
# app/lib/Gas/Storage/User/EloquentUserRepository.php
use User;
class EloquentUserRepository implements UserRepositoryInterface {
public $_eloquentUser;
public function __construct(User $user) {
$this->_eloquentUser = $user;
}
public function all()
{
return User::all();
}
public function find($id)
{
return User::find($id);
}
public function create($input)
{
return User::create($input);
}
public function save()
{
$this->_eloquentUser->save();
}
public function getRoles()
{
return User::$rules;
}
public function getUser()
{
return $this->_eloquentUser;
}
}
我还创建了一个 UsersControllerTest 来测试控制器,一切正常,用户已添加到数据库中。在我嘲笑了我的 UserRepositoryInterface 之后,因为我不需要测试数据库插入,但我只想测试控制器
class UsersControllerTest extends TestCase {
private $mock;
public function setUp() {
parent::setUp();
}
public function tearDown() {
Mockery::close();
}
public function mock($class) {
$mock = Mockery::mock($class);
$this->app->instance($class, $mock);
return $mock;
}
public function testStore() {
$this->mock = $this->mock('Gas\Storage\User\UserRepositoryInterface[save]');
$this->mock
->shouldReceive('save')
->once();
$data['username'] = 'xxxxxx';
$data['first_name'] = 'xxxx';
$data['last_name'] = 'xxxx';
$data['email'] = 'prova@gmail.com';
$data['password'] = 'password';
$data['password_confirmation'] = 'password';
$response = $this->call('POST', 'users', $data);
var_dump($response->getContent());
}
}
我的 ruote 文件:
Route::resource('users', 'UsersController');
当我运行测试时,我收到以下错误:
Mockery\Exception\InvalidCountException : Method save() from Mockery_0_Gas_Storage_User_UserRepositoryInterface should be called
exactly 1 times but called 0 times.
为什么没有调用模拟方法save?
怎么了?
编辑:没有部分模拟一切正常,现在的问题是:为什么部分模拟它不起作用?
谢谢
【问题讨论】:
-
看起来你正在模拟的类的命名空间在“模拟”方法调用中与控制器上的“使用”语句中的命名空间不同。一个以“Gas”开头,另一个以“Way”开头。
-
@patricksayshi 这是我在写问题时犯的错误
-
你试过没有
[save]部分吗?这似乎会使 IoC 容器感到困惑。即,如果您的控制器构造函数被类型提示期望“Gas\Storage\User\UserRepositoryInterface[save]”,它将返回正确的模拟。但是类型提示需要“Gas\Storage\User\UserRepositoryInterface”,因此 IoC 容器将返回您之前绑定到该接口的任何内容。您希望它覆盖原始的 IoC 绑定,但由于 '[save]' 存在,而且它是一个不同的字符串,我希望它只会创建一个新的绑定并且不会将模拟返回到测试。 -
@hakre OP 的代码中没有什么是不能模拟的。我每天都在 laravel 中对对象进行单元测试和模拟。你是对的,你不能模拟对模型的静态调用。但是OP没有这些。对外观的静态调用(Input::all()、Validator::make() 等)确实可以被模拟,这是 Laravel 设计的一部分。我仍然认为这里的问题是“[save]”字符串混淆了 IoC 容器。删除它应该可以解决这个问题,此时 philipbrown 的回答将变得非常重要。
-
@PapaSmurf 我想你是想回复我的。它不适用于部分模拟,因为在 IoC 容器上,您将
UserRepositoryInterface[save]绑定到您创建的模拟。但是您的应用程序代码从不要求 IoC 容器提供UserRepositoryInterface[save]的实例。您可以在控制器构造函数中看到它要求UserRepositoryInterface。我不确定您是否可以在这种情况下使用部分模拟。我很好奇 - 为什么要使用部分模拟?如果是我,我只会嘲笑全班,不再烦恼。
标签: php unit-testing laravel mockery partial-mocks