Testing
Never let a test reach Bullhorn: it is a live CRM with real candidates, and every test run would cost a login.
In Laravel: Http::fake()
The client sends through Laravel’s HTTP client, so Http::fake() and Http::preventStrayRequests() work. The login has four requests; answer them with FakeTransport::login() and describe only your API calls:
use Darvis\BullhornApi\Testing\FakeTransport;
use Illuminate\Http\Client\Request;
use Illuminate\Support\Facades\Http;
beforeEach(function () {
Http::preventStrayRequests();
config([
'bullhorn.client_id' => 'id',
'bullhorn.client_secret' => 'secret',
'bullhorn.username' => 'user',
'bullhorn.password' => 'password',
]);
});
test('a candidate is created in Bullhorn', function () {
Http::fake(function (Request $request) {
$login = FakeTransport::login($request->url());
if ($login !== null) {
return Http::response($login->body, $login->status, $login->headers);
}
return Http::response(['changedEntityId' => 42]);
});
// ... the code under test ...
Http::assertSent(fn (Request $request) => $request->method() === 'PUT'
&& str_ends_with($request->url(), 'entity/Candidate'));
});
Http::fake() keeps the first callback that matches: register one callback per test, not one for the login and another for the API.
Mock the client
To test a screen without HTTP at all, swap the client in the container:
use Darvis\BullhornApi\Client;
$this->mock(Client::class)
->shouldReceive('entity')
->andReturn(['data' => ['id' => 1, 'firstName' => 'Anna']]);
Client is not final for this reason.
Without Laravel: FakeTransport
use Darvis\BullhornApi\Client;
use Darvis\BullhornApi\Config;
use Darvis\BullhornApi\Http\Response;
use Darvis\BullhornApi\Testing\FakeTransport;
$transport = (new FakeTransport)
->respond('entity/Candidate/1', ['data' => ['id' => 1]])
->respond('PUT', new Response(400, '{"errorMessageKey":"errors.cannotPersistEntity"}'));
$client = new Client(new Config('id', 'secret', 'user', 'password'), $transport);
respond($needle, ...$answers)answers every request whoseMETHOD urlcontains$needle. Several answers are given in turn, and the last one repeats. An array is sent as JSON with status 200; aThrowableis thrown as a transport without a response. The rule added last is tried first.- The login answers by itself, with the constants on
FakeTransport(BH_REST_TOKEN,REFRESH_TOKEN,REST_URL…). $transport->requestsholds every request;sent($needle)filters them.
To test a session that expires, answer a call with new Response(401) and then with the result: the client renews and repeats once.