Laravel API测试 - 如何测试具有外部API调用的API

6

我的API代码

public function store (Request $request, $profileId)
{
    $all = $request->all();
    $token = AccessToken::with('users')->where('access_token',$request->input('access_token'))->first();

    if($token && $token->users->isOwnProfile($profileId))
    {
        $rules = [
            'access_token'     => 'required',
            'title'            => 'required',
            'description'      => 'required',
            'file_id'          => 'required',
            'audience_control' => 'required|in:' . join(',', PostRepository::$AUDIENCE_CONTROL),
            'tags'             => 'required',
        ];
        $validator = Validator::make($all, $rules);

        $error = $validator->errors()->toArray();
        if ($validator->fails())
        {
            return $this->setStatusCode(401)
                ->setStatusMessage(trans('api.validation failed'))
                ->respondValidationMessage($error);
        }
        try {
            $response = $this->postRepository->save($request, $profileId);
            if(isset($response['error']))
                return $this->messageSet([
                    'message' => $response['error']['message'],
                ], $response['error']['status_code']);

            return $this->setDataType('post_id')
                ->setStatusCode('200')
                ->respondWithCreatedId(trans('api.Post created'), $response->id);
        } catch (\Exception $e) {
            return $this->respondInternalError(trans('api.processing error'));
        }
    }
    return $this->respondInternalError('404 page');

}

保存方法调用另一个方法,该方法调用外部API。

/*
 * this function returns some response where it has profile_id for 
 * the file which in other save function is matched that the
 * profile_id passed as parameter is same with file profile_id
 */
public function getFileDetails($file_id)
{
    try
    {
        $response = json_decode((new Client())->request('GET', env('xyz','http://abc.xyz/api/v1').'/files/' . $file_id)->getBody()->getContents(), true);
    }
    catch (RequestException $e)
    {
        $response = json_decode($e->getResponse()->getBody()->getContents(), true);
    }

    return $response;

}

现在这是我为API编写的测试函数。

public function testPostCreateChecksProfileMatchesCorrectly()
{
    $this->json('POST', 'profiles/' . $this->getProfile()->id . '/posts' . '?access_token=' . $this->getAccessToken(), [
        'title' => 'api testing title',
        'description' => 'api testing description',
        'audience_control' => 'public',
        'tags' => [
            'Animals',
            'City'
        ],
        'file_id' => '281'
    ])->seeJsonStructure([
        'success' => [
            'message',
            'post_id',
            'status',
        ],
    ]);
}

现在我的问题是,当我进行测试时,如何为外部 API 创建一个虚假响应。我正在使用 PHPUnit 和 Laravel 5.2。

相关链接:https://dev59.com/PJXfa4cB1Zd3GeqPf4C0#36281263 - Jakub Zalas
2个回答

2
您可以使用PHP VCR记录API请求的输出。
https://github.com/php-vcr/php-vcr
使用此软件包,您将能够将其保存在tests / fixtures目录中。
因此,在第一次之后,PHPUnit将读取此文件而不进行其他请求。
这样也将添加到您的GIT repo中。
首先,您需要使用以下方式安装它:
composer require php-vcr/php-vcr 
composer require php-vcr/phpunit-testlistener-vcr 

第二个包将PHPUnit与PHP-VCR集成在一起。
然后在phpunit.xml文件中添加以下内容:
<listeners>
    <listener class="VCR\PHPUnit\TestListener\VCRTestListener" file="vendor/php-vcr/phpunit-testlistener-vcr/src/VCRTestListener.php" />
</listeners>

在 Laravel 应用程序的测试目录中创建名为 'fixtures' 的文件夹。

现在我们可以进行测试,例如:

/** @test */
public function itShouldGetVenueGpsCoordinates()
{

    $address = "Milano, viale Abruzzi, 2";
    VCR::turnOn();
    VCR::insertCassette('mapquestapi');
    $coordinates = $this->venueService->getVenueGpsCoordinates($address);

    VCR::eject();
    VCR::turnOff();

    $this->assertEquals(45, number_format($coordinates['lat'], 0));
    $this->assertEquals(9, number_format($coordinates['lng'], 0));
}

测试将创建一个 fixture,我的情况下称为 'mapquestapi',您将能够将其添加到您的GIT repo中。因此,从第二次开始,当您的测试调用API时,数据将从此文件加载,而不是进行新请求。
如果您订阅了Laracast,则可以在此处查看完整的视频教程。 https://laracasts.com/lessons/testing-http-requests

Davide,谢谢你。不幸的是,测试已经超出了我的范围,因为我不再拥有这个项目,但还是非常感谢。️ - ARIF MAHMUD RANA
1
希望这对未来的其他项目或其他人有用。 - Davide Casiraghi

-5

首先,永远不要测试你不拥有的东西。外部API调用就是你不拥有的东西。可能会出现许多问题或用例,比如提交数据、网络错误或他们的内部错误。每种情况都应该进行测试,这很繁琐。相反,使用一个模拟对象并对其进行一些期望。听听这个播客http://www.fullstackradio.com/37,这将帮助您清楚地了解。

尝试将代码分成小块,然后分别测试每个块。你对单个测试期望太高了。将验证逻辑放在FormRequest类中,这将对你有很大帮助。


6
我认为“永远不要测试你不拥有的东西”是一个可怕的建议。我总是需要一套集成测试来确保我与第三方正确通讯。这是一个小型的测试集,因为我总是引入一个用于第三方通讯的抽象层,但它确实存在。该抽象层可以被模拟(但不能模拟与第三方的交互)。 - Jakub Zalas
1
我同意@JakubZalas的观点。我们总是希望一切都能正常工作。 - Cong LB

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接