phpunit找不到模型方法(Laravel / Mockery)
我开始使用Laravel 4中的单元测试,并且我坚持在添加到标准User模型的模型中测试自定义方法。
use IlluminateAuthUserInterface;
use IlluminateAuthRemindersRemindableInterface;
class User extends BaseModel implements UserInterface, RemindableInterface {
/**
* Logs to the database and streams an update
* Uses logIt and streamIt on Base model
* @param String $action The action being performed
* @return void
*/
private function logAndStream($action)
{
$this->logIt('info', $action.'d user '.$this->username);
$this->streamIt($action.'d user '.$this->username);
}
这个类扩展了BaseModel,它反过来扩展了Eloquent,并且定义了如下的logIt和StreamIt方法:
class BaseModel extends Eloquent {
/**
* Log an action to log file
* @return void
*/
protected function logIt($level, $msg) {
...
}
/**
* Log an action to activity stream
* @return void
*/
protected function streamIt($msg, $client = null, $project = null) {
...
}
所有这些代码工作正常,当我手动测试的东西。 但是现在我想创建一个单元测试来自动化它。
class UserTest extends TestCase {
public function testLogAndStream()
{
$base = Mockery::mock('BaseModel')->shouldAllowMockingProtectedMethods();
$base->shouldReceive('logIt')
->with('info', 'Created user Tester')
->once();
$user = new User;
$user->username = 'Tester';
$user->logAndStream('Create');
}
当我尝试运行这个时,我得到一个失败抱怨没有找到logAndStream。
1) UserTest::testLogAndStream
BadMethodCallException: Call to undefined method IlluminateDatabaseQueryBuilder::logAndStream()
我错过了什么?
这里有两个问题:
首先 ,您的User
模型包含一个logAndStream
方法,但它是私有的。 这意味着这样做:
$user->logAndStream('Create');
是不可能的,因为只有公共方法可以通过这种方式访问。
其次 ,在你的测试中,你正在嘲笑一个BaseModel
的实例。 这与您稍后实例化几行的User
实例无关。 User
扩展BaseModel
- 您仍然可以拥有不相关的User
和BaseModel
实例。 这是一个比喻:
class Database {
}
class DatabaseWithExtraFeatures extends Database {
}
第一个( Database
)只是一个普通的旧数据库访问类,对于基本的东西来说工作得很好。 然后有人出现并意识到Database
没有提供一些额外的功能,所以他们通过扩展它来构建它。 开发人员可以在同一个应用程序中使用,或者甚至两者都使用。
$db = new Database;
$dbExtra = new DatabaseWithExtraFeatures;
// do something with $db
$result1 = $db->query();
// do something with $dbExtra
$result2 = $dbExtra->extraSpecialQuery();
你在测试中做了什么与此类似 - 你嘲笑了一个BaseModel
实例,然后实例化了一个User
类(它恰好扩展了BaseModel
)。
编辑这里有一些关于如何模拟用户模型的更多细节:
$user = Mockery::mock('User')->shouldAllowMockingProtectedMethods();
$user->shouldReceive('logIt')
->with('some arguments')
->once();
$user->shouldReceive('streamIt')
->with('some arguments')
->once();
// when you set a property on an Eloquent model, it actually calls the
// setAttribute method. So do this instead of $user->username = 'Tester'
//
$user->shouldReceive('setAttribute')
->with('username', 'Tester')
->once()
$user->logAndStream('Create');
// now assert something...
因为User
从继承BaseModel
,从方法中BaseModel
实际上是对方法User
和,就好像它们被定义为的一部分可以被处理User
。
免责声明:这是从问题中提取的。
首先,我应该一直检查logIt和streamIt在相同的模拟用户模型而不是父级BaseModel上观察到的位置。
用$user->username
填充模拟用户模型也不正确。 最后,Kryten帮助我意识到Eloquent在内部调用了getAttribute('username')
,所以我可以直接返回值作为断言的一部分,然后将其输入到logIt和StreamIt中。 这有效,但感觉有点笨重 - 如果有人可以提出更好的方法,我很乐意学习。
无论logAndStream
是公开的还是保护的,这都是工作的测试用例:
public function testLogAndStream()
{
$user = Mockery::mock('User');
$user->shouldReceive('getAttribute')
->with('username')
->atLeast()->once()
->andReturn('Tester');
$user->shouldReceive('logIt')
->once()
->with('info','Created user Tester');
$user->shouldReceive('streamIt')
->once()
->with('Created user Tester');
$user->logAndStream('Create');
}
链接地址: http://www.djcxy.com/p/83191.html