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 - 您仍然可以拥有不相关的UserBaseModel实例。 这是一个比喻:

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

上一篇: phpunit not finding model method (Laravel / Mockery)

下一篇: Laravel model event saving is not firing