Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Laravel API Test - How to test API that has external API call

My API code

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');

}

From save method it calls another method that calls an external 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;

}

Now this is my test function for 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',
        ],
    ]);
}

Now my question is how can I create a fake response for the external API when I am testing.

I am using PHPUnit & Laravel 5.2.

like image 997
ARIF MAHMUD RANA Avatar asked Mar 31 '16 11:03

ARIF MAHMUD RANA


1 Answers

You can use PHP VCR to record the output of the API request.
https://github.com/php-vcr/php-vcr.

With this package, you will be able to save it in the tests/fixtures directory.
So after the first time, PHPUnit will read this file instead of doing other requests.
And in this way will be added also to your GIT repo.

First you need to install it using:

composer require php-vcr/php-vcr 
composer require php-vcr/phpunit-testlistener-vcr 

The second package integrates PHPUnit with PHP-VCR.

Then add to your phpunit.xml after

<listeners>
    <listener class="VCR\PHPUnit\TestListener\VCRTestListener" file="vendor/php-vcr/phpunit-testlistener-vcr/src/VCRTestListener.php" />
</listeners>

Then create the dir called 'fixtures' in the tests directory of your Laravel application.

Now we can test like:

/** @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));
}

The test will create then a fixture, in my case called 'mapquestapi', that you will be able to add to your GIT repo. So from the second time, the API will be called by your test, the data will be loaded from this file instead of making a new request.

If you are subscribed to Laracast you can see a complete video tutorial here. https://laracasts.com/lessons/testing-http-requests

like image 157
Davide Casiraghi Avatar answered Oct 04 '22 12:10

Davide Casiraghi