【问题标题】:Mocking external library in PHP/Codeigniter在 PHP/Codeigniter 中模拟外部库
【发布时间】:2017-11-20 12:33:57
【问题描述】:

使用ci-php-unit-test 库对 PHP/codeigniter 进行单元测试,并对控制器方法进行单元测试。

无法弄清楚如何模拟使用 composer 安装的外部库。

我的 SUT 方法是:

function twitter()
{
    $this->load->model('misc/twitter_model');
    $request_token = [];

    $request_token['oauth_token'] = $_SESSION['twitter_oauth_token'];
    $request_token['oauth_token_secret'] = $_SESSION['twitter_oauth_token_secret'];
    if ( (isset($_GET['oauth_token']) 
        && ($request_token['oauth_token'] !== $_GET['oauth_token'])))
    {
        log_message('info','abort something is wrong!');
    }
    else
    {
        $connection = new Abraham\TwitterOAuth\TwitterOAuth(TWITTER_CONSUMER_KEY, TWITTER_CONSUMER_SECRET, $request_token['oauth_token'], $request_token['oauth_token_secret']);
        $access_token = $connection->oauth("oauth/access_token", array("oauth_verifier" => $_REQUEST['oauth_verifier']));
        $this->session->set_userdata('twitter_access_token',$access_token);
        redirect(get_session('twitter_callback1'));
    }
}

我的测试方法(到目前为止)是:

public function test_twitter()
{
    $_SESSION['twitter_oauth_token'] = 'twitter_oauth_token';
    $_SESSION['twitter_oauth_token_secret'] = 'twitter_oauth_token_secret';

    $this->request->setCallable(
        function (& $CI) {
            // Get mock object
            $twitter_oa = $this->getMockBuilder('TwitterOAuth')
                ->disableOriginalConstructor()
                ->setMethods(['oauth'])
                ->getMock();
            $twitter_oa->method('oauth')
                 ->willReturn('access_token');
        }
    );
    $output = $this->request('GET','callbacks/twitter',['oauth_token'=>'twitter_oauth_token']);
    var_export($output);
}

但是原始库正在执行,因为它没有被模拟 - $twitter_oa 没有附加到 CI 实例。

这是因为在codeigniter控制器实例化后外部库还没有被实例化。 (这是 setCallable 方法所做的)

我的问题是,如何在实例化 codeigniter 控制器后模拟 TwitterOAuth,以便它可以返回设置的测试文本? (显然没有实例化 twitter Oauth 库)

【问题讨论】:

    标签: php codeigniter unit-testing phpunit


    【解决方案1】:

    好的,所以当你看到一个新的 Class();在单元测试中,您必须重新工作。这可能不是最好的选择,但这对我有用。

    在 SUT 中,控制器代码现在是:

    function twitter()
    {
        $this->load->model('misc/twitter_model');
        $request_token = [];
    
        $request_token['oauth_token'] = $_SESSION['twitter_oauth_token'];
        $request_token['oauth_token_secret'] = $_SESSION['twitter_oauth_token_secret'];
        if ( (isset($_GET['oauth_token']) 
            && ($request_token['oauth_token'] !== $_GET['oauth_token'])))
        {
            log_message('info','abort something is wrong!');
        }
        else
        {
            $connection = $this->twitter_connection($request_token['oauth_token'],$request_token['oauth_token_secret']);
            $access_token = $connection->oauth("oauth/access_token", array("oauth_verifier" => $_REQUEST['oauth_verifier']));
            $this->session->set_userdata('twitter_access_token',$access_token);
            redirect(get_session('twitter_callback1'));
        }
    }
    
    /**
     * @param $token
     * @param $secret
     * @return \Abraham\TwitterOAuth\TwitterOAuth
     *
     * @codeCoverageIgnore
     *
     */
    public function twitter_connection($token, $secret)
    {
        return new Abraham\TwitterOAuth\TwitterOAuth(
            TWITTER_CONSUMER_KEY,
            TWITTER_CONSUMER_SECRET,
            $token,
            $secret);
    }
    

    APPPATH.tests/mocks/external_libaries 中有一个新文件:

    class MockTwitterOAuth
    {
        public function oauth()
        {
            return 'access_token';
        }
    }
    

    现在测试代码是:

    public function test_twitter()
    {
        $_SESSION['twitter_oauth_token'] = 'twitter_oauth_token';
        $_SESSION['twitter_oauth_token_secret'] = 'twitter_oauth_token_secret';
        $_SESSION['twitter_callback1'] = 'cb1';
        require_once(APPPATH.'tests/mocks/external_libraries/MockTwitterOauth.php');
        $twitter_connection = new MockTwitterOAuth();
        MonkeyPatch::patchMethod('Callbacks',[
            'twitter_connection'=>$twitter_connection
        ]);
        $output = $this->request('GET','callbacks/twitter',['oauth_token'=>'twitter_oauth_token']);
        $this->assertNull($output);
        $this->assertResponseCode(HTTP_FOUND);
        $this->assertRedirect(base_url('cb1'));
        $this->assertEquals('access_token',$_SESSION['twitter_access_token']);
    }
    

    诀窍是让 twitter 连接正常返回一个新的 TwitterOAuth 类,但是当系统进行单元测试时,返回只有一个方法的 MockTwitterOAuth 类。这可以通过猴子补丁控制器代码来完成。

    希望这个答案对其他人有用,如果您还没有使用它,https://github.com/kenjis/ci-phpunit-test 非常好,即使它很难开始。推荐购买配套书!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2023-02-19
      • 2011-01-21
      • 1970-01-01
      • 1970-01-01
      • 2015-02-16
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多