Lawman: Pest Architecture Testing for Saloon API Integrations
Introduction
If you've been reading my content for a while, you'll likely know that I love building and testing API integrations in Laravel. They're both really fun tasks that can be rewarding when you get them right.
Using Saloon for building API integrations in my Laravel projects has made this even more fun! It's a really powerful tool that makes it easy to build and test API integrations in Laravel. In fact, a huge amount of my book, Consuming APIs in Laravel, is dedicated to using Saloon to build and test API integrations.
Thanks to a cool package called "Lawman" by Jon Purvis, we can take the testing even further to add some really powerful Pest architecture tests to our Saloon integration code.
In this article, we're going to take a look at some examples of how you might want to use Lawman in your PHP and Laravel projects.
If you're not already familiar with what architecture testing is and what it achieves, you might want to check out my "Architecture Testing in Laravel with Pest" article which explains it in more detail.
Installation
To get started with Lawman, you'll first need to install it. You can do this using Composer by running the following command in your project root:
composer require jonpurvis/lawman --dev
It's worth noting that we're using the --dev
flag here to ensure that Lawman is only installed in your development environment. This is because Lawman is a testing tool and you don't want it to be included in your production environment.
Usage Examples
Now that you've got Lawman installed, you can start using it to test your Saloon integrations.
To get a good idea of the architecture testing expectations it provides, let's take a look at some examples.
We'll imagine we've built a simple GitHub API integration in a Laravel application using Saloon. We might have the following files that contain our integration code:
Connector:
-
app/Http/Integrations/GitHub/GitHubConnector.php
Requests:
-
app/Http/Integrations/GitHub/Requests/CreateRepoRequest.php
-
app/Http/Integrations/GitHub/Requests/GetReposRequest.php
Let's look at a test that we could write for our app/Http/Integrations/GitHub/GitHubConnector.php
file using Lawman's expectations:
use App\Http\Integrations\GitHub\GitHubConnector;
test('connectors')
->expect(GitHubConnector::class)
->toBeSaloonConnector()
->toUseAcceptsJsonTrait()
->toUseAlwaysThrowOnErrorsTrait()
->toBeTriedAgainOnFailure()
->toHaveRetryInterval()
->toUseExponentialBackoff()
->toHaveRateLimits();
In the architecture test above, we're asserting that our App\Http\Integrations\GitHub\GitHubConnector
meets several criteria:
- It extends the
Saloon\Http\Connector
class. - It uses the
Saloon\Traits\Plugins\AcceptsJson
trait. - It uses the
Saloon\Traits\Plugins\AlwaysThrowOnErrors
trait. - It has a
tries
property that is greater than 1 (for retrying requests on failure). - It has a
retryInterval
property (used for specifying how long to wait between retries). - It has a
useExponentialBackoff
property (used for specifying whether to use exponential backoff for the request retries). - It uses the
Saloon\RateLimitPlugin\Traits\HasRateLimits
plugin.
If any of the above criteria aren't met, the test will fail.
You may also want to write a test to ensure that all the PHP files within the App\Http\Integrations\GitHub\Requests
directory are Saloon request classes:
test('requests')
->expect('App\Http\Integrations\GitHub\Requests')
->toBeSaloonRequest();
The cool thing about Lawman is that you're not restricted to only using Lawman's expectations - you can still use Pest's default expectations too. For example, we could use some of Pest's default expectations to the update the test above:
test('requests')
->expect('App\Http\Integrations\GitHub\Requests')
->toBeSaloonRequest()
->toHaveSuffix('Request')
->toUseStrictTypes()
->toBeFinal();
In the test above, we're asserting that all the PHP files within the App\Http\Integrations\GitHub\Requests
namespace meet the following criteria:
- Must be a Saloon request class
- The classname must end with "Request"
- The files are using strict types
- The files are marked as
final
Lawman also allows you to ensure that given files in a namespace are using the correct HTTP methods. For example, you may want to assert that a request class sends a GET request and also has caching enabled:
use App\Http\Integrations\GitHub\Requests\GetReposRequest;
test('get requests')
->expect(GetReposRequest::class)
->toSendGetRequest()
->toHaveCaching();
Another example might be to assert that a request class sends a POST request and has a JSON body:
use App\Http\Integrations\GitHub\Requests\CreateRepoRequest;
test('post requests')
->expect(CreateRepoRequest::class)
->toSendPostRequest()
->toHaveJsonBody();
Available Expectations
We can't cover all the expectations that Lawman provides (this article would end up being huge!). But here's a list of the other expectations that are available to you:
Authentication
-
toUseTokenAuthentication
-
toUseBasicAuthentication
-
toUseCertificateAuthentication
-
toUseHeaderAuthentication
Caching
-
toHaveCaching
Connector
-
toBeSaloonConnector
Pagination
-
toUsePagedPagination
-
toUseOffsetPagination
-
toUseCursorPagination
-
toUseCustomPagination
Properties
-
toSetConnectTimeout
-
toSetRequestTimeout
-
toBeTriedAgainOnFailure
-
toHaveRetryInterval
-
toUseExponentialBackoff
-
toThrowOnMaxTries
Rate Limiting
-
toHaveRateLimits
Requests
-
toBeSaloonRequest
-
toHaveRequestMethod
-
toSendGetRequest
-
toSendPostRequest
-
toSendHeadRequest
-
toSendPutRequest
-
toSendPatchRequest
-
toSendDeleteRequest
-
toSendOptionsRequest
-
toSendConnectRequest
-
toSendTraceRequest
-
toHaveJsonBody
-
toHaveMultipartBody
-
toHaveXmlBody
-
toHaveFormBody
-
toHaveStringBody
-
toHaveStreamBody
Response
-
toBeSaloonResponse
Traits
-
toUseAcceptsJsonTrait
-
toUseAlwaysThrowOnErrorsTrait
-
toUseTimeoutTrait
-
toUseAuthorisationCodeGrantTrait
-
toUseClientCredentialsGrantTrait
Conclusion
Hopefully, this article has given you an insight into how to use Lawman to add some powerful Pest architecture tests to your Saloon integration code.
If you enjoyed reading this post, you might be interested in checking out my 440+ page ebook "Consuming APIs in Laravel" which teaches you how to use Laravel to consume APIs from other services.
If you're interested in getting updated each time I publish a new post, feel free to sign up for my newsletter below.
Keep on building awesome stuff! 🚀
driesvints, teephe liked this article