当涉及到调用其他方法的存根时,我的规范测试似乎有问题。
我一直在为我的控制器遵循Laracasts的"六边形"方法,以确保它只负责HTTP层。
控制器
<?php
use ApesUtilitiesConnect;
use OAuth;
class FacebookConnectController extends BaseController {
/**
* @var $connect
*/
protected $connect;
/**
* Instantiates $connect
*
* @param $connect
*/
function __construct()
{
$this->connect = new Connect($this, OAuth::consumer('Facebook'));
}
/**
* Login user with facebook
*
* @return void
*/
public function initialise() {
// TODO: Actually probably not needed as we'll control
// whether this controller is called via a filter or similar
if(Auth::user()) return Redirect::to('/');
return $this->connect->loginOrCreate(Input::all());
}
/**
* User authenticated, return to main game view
* @return Response
*/
public function facebookConnectSucceeds()
{
return Redirect::to('/');
}
}
因此,当路由初始化时,我构建了一个新的Connect实例,并将$this类的实例传递给我的Connect类(作为侦听器),并调用loginOrCreate方法。
顶点\实用程序\连接
<?php
namespace ApesUtilities;
use ApesCreatorsAccount;
use IlluminateDatabaseEloquentModel;
use User;
use Auth;
use CarbonCarbon as Carbon;
class Connect
{
/**
* @var $facebookConnect
*/
protected $facebookConnect;
/**
* @var $account
*/
protected $account;
/**
* @var $facebookAuthorizationUri
*/
// protected $facebookAuthorizationUri;
/**
* @var $listener
*/
protected $listener;
public function __construct($listener, $facebookConnect)
{
$this->listener = $listener;
$this->facebookConnect = $facebookConnect;
$this->account = new Account();
}
public function loginOrCreate($input)
{
// Not the focus of this test
if(!isset($input['code'])){
return $this->handleOtherRequests($input);
}
// Trying to stub this method is my main issue
$facebookUserData = $this->getFacebookUserData($input['code']);
$user = User::where('email', '=', $facebookUserData->email)->first();
if(!$user){
// Not the focus of this test
$user = $this->createAccount($facebookUserData);
}
Auth::login($user, true);
// I want to test that this method is called
return $this->listener->facebookConnectSucceeds();
}
public function getFacebookUserData($code)
{
// I can't seem to stub this method because it's making another method call
$token = $this->facebookConnect->requestAccessToken($code);
return (object) json_decode($this->facebookConnect->request( '/me' ), true);
}
// Various other methods not relevant to this question
我试着把它精简一下,把重点放在测试中的方法上,以及到目前为止我对哪里出了问题的理解上。
连接等级库
<?php
namespace specApesUtilities;
use PhpSpecObjectBehavior;
use ProphecyArgument;
use IlluminateRoutingControllersController;
use OAuth;
use ApesCreatorsAccount;
class ConnectSpec extends ObjectBehavior
{
function let(FacebookConnectController $listener, OAuth $facebookConnect, ApesCreatorsAccount $account)
{
$this->beConstructedWith($listener, $facebookConnect, $account);
}
function it_should_login_the_user($listener)
{
$input = ['code' => 'afacebooktoken'];
$returnCurrentUser = (object) [
'email' => 'existinguser@domain.tld',
];
$this->getFacebookUserData($input)->willReturn($returnCurrentUser);
$listener->facebookConnectSucceeds()->shouldBeCalled();
$this->loginOrCreate($input);
}
这是我遇到问题的规范。首先,我假装我已经有了一个脸书代币。然后,事情失败的地方是,我需要伪造getFacebookUserData方法将返回一个存在于我的users表中的示例用户。
然而,当我运行测试时,我得到:
Apes/Utilities/Connect
37 ! it should login the user
method `DoubleArtdarekOAuthFacadeOAuthP13::requestAccessToken()` not found.
我曾希望"willReturn"会忽略getFacebookUserData方法中发生的任何事情,因为我正在单独测试,但似乎不是。
关于我应该做什么有什么建议吗?
我需要将所有的OAuth类方法拉到它们自己的类中吗?考虑到OAuth已经是它自己的类,我可能需要这样做,这对我来说似乎很奇怪。有没有办法在getFacebookUserData中存根该方法?
更新1
所以我尝试了在getFacebookUserData中调用的方法,我更新的规范看起来是这样的:
function it_should_login_the_user($listener, $facebookConnect)
{
$returnCurrentUser = (object) [
'email' => 'existinguser@domain.tld',
];
$input = ['code' => 'afacebooktoken'];
// Try stubbing any methods that are called in getFacebookUserData
$facebookConnect->requestAccessToken($input)->willReturn('alongstring');
$facebookConnect->request($input)->willReturn($returnCurrentUser);
$this->getFacebookUserData($input)->willReturn($returnCurrentUser);
$listener->facebookConnectSucceeds()->shouldBeCalled();
$this->loginOrCreate($input);
}
规范仍然失败,但错误已更改:
Apes/Utilities/Connect
37 ! it should login the user
method `DoubleArtdarekOAuthFacadeOAuthP13::requestAccessToken()` is not defined.
有趣的是,如果我把这些新的存根放在$this->getFacebookUserData存根之后,那么错误是"未找到",而不是"未定义"。很明显,我不完全理解手头的内部工作:D
并不是所有依赖项中被调用的方法都必须被嘲笑,因为它们实际上会在测试类时被调用:
...
$facebookConnect->requestAccessToken($input)->willReturn(<whatever it should return>);
$this->getFacebookUserData($input)->willReturn($returnCurrentUser);
...
如果不嘲笑它们,phpspec将引发一个not found
。
我不熟悉所涉及的类,但这个错误意味着没有方法Oauth::requestAccessToken()。
预言不会让你截断不存在的方法。