0

当涉及到调用其他方法的存根时,我的规范测试似乎存在问题。

我一直在为我的控制器遵循 Laracasts 的“六边形”方法,以确保它只负责 HTTP 层。

控制器

<?php

use Apes\Utilities\Connect;
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 Apes\Utilities;

use Apes\Creators\Account;
use Illuminate\Database\Eloquent\Model;
use \User;
use \Auth;
use \Carbon\Carbon 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 spec\Apes\Utilities;

use PhpSpec\ObjectBehavior;
use Prophecy\Argument;
use \Illuminate\Routing\Controllers\Controller;
use \OAuth;
use \Apes\Creators\Account;


class ConnectSpec extends ObjectBehavior
{
    function let(\FacebookConnectController $listener, \OAuth $facebookConnect, \Apes\Creators\Account $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);
    }

所以这是我遇到问题的规范。首先,我假装我已经有一个 facebook 令牌。然后,事情失败的地方是我需要捏造 getFacebookUserData 方法将返回一个存在于我的用户表中的示例用户。

但是,当我运行测试时,我得到:

Apes/Utilities/Connect                               
  37  ! it should login the user
      method `Double\Artdarek\OAuth\Facade\OAuth\P13::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 `Double\Artdarek\OAuth\Facade\OAuth\P13::requestAccessToken()` is not defined.

有趣的是,如果我将这些新存根放在 $this->getFacebookUserData 存根之后,那么错误是“未找到”而不是“未定义”。显然我不完全理解手头的内部运作:D

4

2 回答 2

0

I'm not familiar with the classes involved but that error implies there is not method Oauth:: requestAccessToken().

Prophecy will not let you stub non-existent methods.

于 2014-04-19T08:25:16.370 回答
0

并非所有依赖项中的调用方法都必须被模拟,因为它们实际上会在测试类时被调用:

...

$facebookConnect->requestAccessToken($input)->willReturn(<whatever it should return>);

$this->getFacebookUserData($input)->willReturn($returnCurrentUser);

...

如果你不模拟它们,phpspec 将引发一个not found.

于 2014-04-11T02:49:16.353 回答