I have used $this->json in the past to test controllers - specifically to write unit test for API controllers. It is simple and when combined with it's other functions like assertStatus and such, is simple. It works for 90% of my use cases.
However I am now attempting to test an API route that results in the controller calling an external API with some of the passed data. In this circumstance I do not want the controller to run like normal - I would like to intercept the external API call and return dummy data to cut out the calls and control the result.
I realize that using my current approach will not work b/c it is calling the API as a normal HTTP request and so there is no connection between that and the running test, so I can't mock the HTTP object.
I have. HTTP mocking does not work b/c it only works within the concept of the test - aka mock the HTTP and send the request. In this circumstance I am attempting to capture the API call that is placed as the result of the test API call - there is not direct connection between them. This may be why it is not do-able.
I am attempting to capture the API call that is placed as the result of the test API call
How are you making the request to the external API inside the controller?
What exactly do you want to assert against (i) the expected response from the external API (ii) the request (URI, payload, headers, etc.) (iii) something else?
However I am now attempting to test an API route that results in the controller calling an external API with some of the passed data. In this circumstance I do not want the controller to run like normal - I would like to intercept the external API call and return dummy data to cut out the calls and control the result.
@robertldeboer Your interaction with the external API should be done in a class that’s injected into your controller and, in turn, able to mocked. That way, you’ll be able to mock the response the from the external API to test that your controller behaves as you expect.
$this->mock(ExternalApi::class, function ($mock) {
$mock->shouldReceive('someMethod')->andReturn('someResponse');
});
$this->getJson('/api/endpoint')->assertOk();
To provide more context - here is my API controller for the route POST: /api/tracking
class Tracking extends Controller
{
/**
* Add tracking number(s) to an order
*
* @param OrderTracking $request
* @return GenericResponse
* @throws ShippingApiException
* @throws ShippingApiParseException
*/
public function add(OrderTracking $request): GenericResponse
{
$order = new Order();
try {
$orderID = $request->input('order');
$trackingNumber = $request->input('tracking');
$order->setTracking($orderID, $trackingNumber);
return new GenericResponse(['order' => $orderID, 'tracking' => $trackingNumber]);
} catch (ShippingApiException $e) {
if (strstr($e->getMessage(), 'Violation of PRIMARY KEY constraint') !== false) {
throw new ShippingApiException('This tracking number has already been added to this order');
} else {
throw $e;
}
}
}
}
I can test the route is called via $this->json(......
I am trying to catch the $order-setTracking portion that fires off an GuzzleHTTP client request to the shipping system so it doesn't actually send a request and I can returned specific responses to test for various scenarios.