Saloon makes it easy to fake API integrations in your tests. In your tests, you will need to create an instance of MockClient . The MockClient accepts an array of MockResponses which when used on a request, will respond with a fake response without actually sending a real request to the web. This helps speed up tests massively and can help you test your application for different API response scenarios, like a 404 error or 500 error.
Registering a MockClient
Request mocking starts with a MockClient. This class can be applied directly to a connector instance to be used across all requests, or it can be applied on a per-request basis.
<?phpuseSaloon\Http\Faking\MockClient;useSaloon\Http\Faking\MockResponse;$mockClient =newMockClient([MockResponse::make(['name'=>'Sam'],200),MockResponse::make(['name'=>'Alex'],200),MockResponse::make(['error'=>'Server Unavailable'],500),]);$forge =newForgeConnector;$forge->withMockClient($mockClient);// All requests sent with the $forge instance will use the Mock Client
<?phpuseSaloon\Http\Faking\MockClient;useSaloon\Http\Faking\MockResponse;$mockClient =newMockClient([MockResponse::make(['name'=>'Sam'],200),MockResponse::make(['name'=>'Alex'],200),MockResponse::make(['error'=>'Server Unavailable'],500),]);$forge =newForgeConnector;$request =newGetAllServersRequest;// Send a request with a MockClient$forge->send($request, $mockClient);
Using Laravel?
If you are using Laravel, as well as the Saloon Laravel helper library, you don't have to use withMockClient on every instance of your connector. You may use the Saloon facade fake method to define your mock responses. This is a built-in global MockClient that when used will be applied to all Saloon requests sent in your application.
<?phpuseSaloon\Laravel\Saloon;Saloon::fake([MockResponse::make(['name'=>'Sam'],200),MockResponse::make(['name'=>'Alex'],200),MockResponse::make(['error'=>'Server Unavailable'],500),]);// All requests sent with the $forge instance will use the global MockClient$forge =newForgeConnector;$forge->send(newGetUserRequest)// Will return with `['name' => 'Sam']` and status `200`
The MockResponse class
The MockResponse class is used to create fake responses Saloon understands. It can accept a body, status, and headers. These properties will be populated in the fake response. The response body accepts an array for a JSON body or plain strings to simulate other responses, like XML.
Basic sequence testing allows you to define a number of fake responses. When your application uses Saloon, it will pull out the next response in the sequence, removing it from the sequence. Each response can only be consumed once.
useSaloon\Http\Faking\MockClient;useSaloon\Http\Faking\MockResponse;$mockClient =newMockClient([MockResponse::make(['name'=>'Sam'],200),MockResponse::make(['name'=>'Alex'],200),MockResponse::make(['error'=>'Server Unavailable'],500),]);$forge =newForgeConnector;$forge->withMockClient($mockClient);$otherService =newOtherServiceConnector;$otherService->withMockClient($mockClient);$forge->send(newGetUserRequest)// Will return with `['name' => 'Sam']` and status `200`$forge->send(newGetUserRequest)// Will return with `['name' => 'Alex']` and status `200`$otherService->send(newGetUserRequest)// Will return with `['error' => 'Server Unavailable']` and status `500`
Connector Mocking
You may also explicitly define the connector to target with mock responses. Unlike sequence tests, these are always used and are never consumed.
useSaloon\Http\Faking\MockClient;useSaloon\Http\Faking\MockResponse;$mockClient =newMockClient([ForgeConnector::class=>MockResponse::make(['name'=>'Sam'],200),OtherServiceConnector::class=>MockResponse::make(['name'=>'Alex'],200),]);$forge =newForgeConnector;$forge->withMockClient($mockClient);$otherService =newOtherServiceConnector;$otherService->withMockClient($mockClient);$forge->send(newGetUserRequest)// Will return with `['name' => 'Sam']` and status `200`$forge->send(newGetUserRequest)// Will return with `['name' => 'Sam']` and status `200`$otherService->send(newOtherServiceRequest)// Will return with `['name' => 'Alex']` and status `200`
Request Mocking
You may also explicitly define the request to target with mock responses that are used. Unlike sequence tests, these are always used and are never consumed.
useSaloon\Http\Faking\MockClient;useSaloon\Http\Faking\MockResponse;$mockClient =newMockClient([GetForgeServerRequest::class=>MockResponse::make(['name'=>'Sam'],200),OtherServiceRequest::class=>MockResponse::make(['name'=>'Alex'],200),]);$forge =newForgeConnector;$forge->withMockClient($mockClient);$otherService =newOtherServiceConnector;$otherService->withMockClient($mockClient);$forge->send(newGetUserRequest)// Will return with `['name' => 'Sam']` and status `200`$otherService->send(newOtherServiceRequest)// Will return with `['name' => 'Alex']` and status `200`
URL Mocking
You can also define fake responses for particular URL patterns. Whenever a request is made for a particular pattern, Saloon will respond to that request.
useSaloon\Http\Faking\MockClient;useSaloon\Http\Faking\MockResponse;$mockClient =newMockClient(['forge.laravel.com/api/*'=>MockResponse::make(['name'=>'Sam'],200),'samcarre.dev/*'=>MockResponse::make(['name'=>'Alex'],200),'samcarre.dev/exact'=>MockResponse::make(['name'=>'Taylor'],200),// Exact requests'*'=>MockResponse::make(['name'=>'Wildcard'],200),// Any other requests]);$forge =newForgeConnector;$forge->withMockClient($mockClient);$otherService =newOtherServiceConnector;$otherService->withMockClient($mockClient);$forge->send(newGetForgeServerRequest)// Will return with `['name' => 'Sam']` and status `200`$otherService->send(newOtherServiceRequest)// Will return with `['name' => 'Alex']` and status `200`$forge->send(newExactRequest)// Will return with `['name' => 'Taylor']` and status `200`$forge->send(newWildcardServiceRequest)// Will return with `['name' => 'Wildcard']` and status `200`
Adding Expectations
When using faking responses, it's important to be able to check that a specific make request was sent and with the correct data, headers, and config. Saloon provides you with various ways to add expectations to your tests.
Available Expectations
AssertSent
AssertNotSent
AssertSentJson
AssertNothingSent
AssertSentCount
To use one of the expectations, you can simply call the method on your Mock Client.
The AssertSent / AssertNotSent are the two most powerful expectation methods. They can accept a Saloon request, a URL pattern or even a closure where you define if a request/response is what you expect.
Your test may require you to mock your own exceptions that might get thrown. To mock an exception, chain the throw method after you have defined your mock response.
Sometimes, you may need to return a custom mock response based on the request that is currently trying to be sent. With closure/callable mocking, you can do this. Just provide an anonymous function or an invokable class when defining the mock response, and you will get access to the current PendingRequest before it is converted into a mock response. This is great if you have stored fixtures based on the request and need to load the fixture data up. This will work with all of the methods above of mocking the request.
Once you have written your tests - it's a good idea to ensure that no real API requests are made in the future while running those tests. This is because you could be making requests when you don't intend to which could incur charges or worse, make real changes to data you don't expect. With Saloon, you can prevent stray API requests with the global Config helper. Simply in your tests, call the Config::preventStrayRequests() method and you should be good to go!
It's recommended that you place this in your Pest.php file or in your setUp() method to make sure it's used on every test.