Test your application
Introduction​
BowPHP's functional testing API lets you test your APIs in a fluent way using HTTP requests. This API is built on top of PHPUnit, which allows you to leverage the full power of that framework to run your tests. The main HTTP operations (GET, POST, PUT, DELETE, PATCH) are covered, and you can add headers or attachments to your requests.
The TestCase class​
The main class for using the testing API is TestCase, which extends PHPUnit's PHPUnitTestCase class. It provides a simple interface for sending HTTP requests and verifying responses.
Methods of the TestCase class​
The base URL for HTTP calls is resolved in the following order:
- The test's
protected ?string $urlproperty (if defined). - The
APP_URLenvironment variable. - The fallback
http://127.0.0.1:8080(the default port ofphp bow run:server).
To customize the resolution, override the protected method
getBaseUrl(): string in your test class.
1. attach(array $attach)​
Adds files / multipart fields to the next request. The attachments are consumed after the call and do not leak into subsequent requests within the same test.
$test->attach([
'file' => new \CURLFile('/path/to/file.jpg')
])->post('/upload');
2. withHeaders(array $headers)​
Replaces the headers applied to all subsequent requests in the test.
$test->withHeaders([
'Authorization' => 'Bearer token',
'Content-Type' => 'application/json',
]);
3. withHeader(string $key, string $value)​
Adds (or replaces) a single header.
$test->withHeader('X-Custom-Header', 'custom_value');
4. get(string $url, array $param = [])​
GET request. The parameters are appended to the query string.
$response = $test->get('/api/users', ['page' => 1]);
5. post(string $url, array $param = [])​
POST request. Combine it with attach() to send files.
$response = $test->post('/api/users', ['name' => 'John Doe']);
6. put(string $url, array $param = [])​
PUT request.
$response = $test->put('/api/users/1', ['name' => 'John Updated']);
7. delete(string $url, array $param = [])​
A real HTTP DELETE request (no more _method POST hack).
$response = $test->delete('/api/users/1');
8. patch(string $url, array $param = [])​
A real HTTP PATCH request.
$response = $test->patch('/api/users/1', ['name' => 'John Modified']);
9. head(string $url, array $param = [])​
HEAD request: retrieves only the headers, without a body. Useful for checking the existence of a resource or its metadata.
$response = $test->head('/api/users/1');
$response->assertStatus(200);
10. options(string $url)​
OPTIONS request — typically used for CORS preflight.
$response = $test->options('/api/users');
11. visit(string $method, string $url, array $params = [])​
A generic dispatcher based on the HTTP verb. Accepts
get, post, put, patch, delete, head, options.
$response = $test->visit('patch', '/api/users/1', ['name' => 'X']);
Full usage example​
Here is a complete example showing how to set up a functional test with the testing API:
use Bow\Testing\TestCase;
class UserApiTest extends TestCase
{
protected ?string $url = 'http://localhost:8080';
public function testCreateUser()
{
// Add an authorization header
$this->withHeader('Authorization', 'Bearer token');
// Add test data to send in the POST request
$data = [
'name' => 'John Doe',
'email' => 'john.doe@example.com'
];
// Perform the POST request
$response = $this->post('/api/users', $data);
// Check that the response has HTTP status 201
$response->assertStatus(201);
$result = $response->toArray();
// Check that the name of the created user is correct
$this->assertEquals('John Doe', $result['name']);
}
public function testGetUser()
{
// Make a GET request to retrieve a user
$response = $this->get('/api/users/1');
// Check that the response has HTTP status 200
$response->assertStatus(200);
$result = $response->toArray();
// Check that the user's ID is correct
$this->assertEquals(1, $result['id']);
}
}
The Response class for functional tests​
The Response class lets you work with HTTP responses in the context of functional tests with BowPHP. It wraps an object of the HttpClientResponse class and exposes several methods to make assertions on the response.
Methods of the Response class​
1. assertJson(string $message = ''): Response​
Checks that the response content is in JSON format. If it is not, a test failure will be generated.
$response->assertJson("La réponse devrait être au format JSON");
2. assertExactJson(array $data, string $message = ''): Response​
Checks that the response's JSON content exactly matches the specified data.
$response->assertExactJson([
'name' => 'John Doe',
'email' => 'john.doe@example.com'
], "La réponse JSON ne correspond pas aux données attendues.");
3. assertContainsExactText(string $data, string $message = ''): Response​
Checks that the response content exactly matches the given text.
$response->assertContainsExactText("Bienvenue, John Doe", "Le texte de la réponse ne correspond pas.");
4. assertHeader(string $header, string $message = ''): Response​
Checks that a specific header exists in the response.
$response->assertHeader('Content-Type', "L'en-tête Content-Type est manquant.");
5. assertArray(string $message = ''): Response​
Checks that the response content is an array.
$response->assertArray("La réponse devrait être un tableau.");
6. assertContentType(string $content_type, string $message = ''): Response​
Checks that the response content type matches the specified one.
$response->assertContentType('application/json', "Le type de contenu n'est pas 'application/json'.");
7. assertContentTypeJson(string $message = ''): Response​
Checks that the content type is application/json.
$response->assertContentTypeJson("Le type de contenu devrait être JSON.");
8. assertContentTypeText(string $message = ''): Response​
Checks that the content type is text/plain.
$response->assertContentTypeText("Le type de contenu devrait être text/plain.");
9. assertContentTypeHtml(string $message = ''): Response​
Checks that the content type is text/html.
$response->assertContentTypeHtml("Le type de contenu devrait être text/html.");
10. assertContentTypeXml(string $message = ''): Response​
Checks that the content type is text/xml.
$response->assertContentTypeXml("Le type de contenu devrait être text/xml.");
11. assertStatus(int $code, string $message = ''): Response​
Checks that the response's HTTP status code matches the specified one.
$response->assertStatus(200, "Le statut HTTP n'est pas 200.");
12. assertKeyExists(string $key, string $message = ''): Response​
Checks that a key exists in the response's JSON content.
$response->assertKeyExists('id', "La clé 'id' est manquante dans la réponse.");
13. assertKeyMatchValue(string|int $key, mixed $value, string $message = ''): Response​
Checks that a specific key in the response's JSON content matches a specified value.
$response->assertKeyMatchValue('name', 'John Doe', "Le nom dans la réponse ne correspond pas.");
14. assertContains(string $text): Response​
Checks that the response content contains a specific substring.
$response->assertContains("Bienvenue", "Le texte 'Bienvenue' devrait être présent.");
15. getContent(): string​
Retrieves the raw content of the response.
$content = $response->getContent();
16. toArray(): array|object​
Returns the response content as an array or an object (if the content is JSON).
$data = $response->toArray();
17. __call(string $method, array $params = [])​
Allows you to dynamically call the methods of the HttpClientResponse object wrapped in the response.
$response->getCode(); // Calls getCode() on HttpClientResponse
Full usage example​
Here is a complete example showing how to use the Response class to test an API:
use Bow\Testing\TestCase;
class UserApiTest extends TestCase
{
public function testCreateUser()
{
// Perform a POST request
$data = [
'name' => 'John Doe',
'email' => 'john.doe@example.com'
];
$response = $this->post('/api/users', $data);
// Check that the response has status 201
$response->assertStatus(201, "Le statut HTTP devrait être 201");
// Check that the content is JSON
$response->assertJson("La réponse devrait être en JSON");
// Check that the name in the response is correct
$response->assertKeyMatchValue('name', 'John Doe', "Le nom de l'utilisateur est incorrect.");
}
public function testGetUser()
{
// Perform a GET request
$response = $this->get('/api/users/1');
// Check that the response has status 200
$response->assertStatus(200, "Le statut HTTP devrait être 200");
// Check that the user exists
$response->assertKeyExists('id', "L'ID de l'utilisateur devrait exister.");
}
}
References​
Check out the official PHPUnit documentation for more information about assertions and advanced features.
Is something missing?
If you run into problems with the documentation or have suggestions to improve the documentation or the project in general, please open an issue for us, or send a tweet mentioning the Twitter account @bowframework or directly on github.