Application Testing
Relevant source files
The following files were used as context for generating this wiki page:
CodeIgniter 4 provides a comprehensive testing framework built on top of PHPUnit. It includes a variety of helper traits and classes designed to simplify the process of writing unit, integration, and feature tests for your application. The framework encourages a test-driven development approach by providing tools to test everything from database interactions and controller logic to full HTTP request-response cycles.
The testing suite is located in the tests directory and is pre-configured for use with PHPUnit. The core of the testing support is the CIUnitTestCase class, which all test cases should extend. This base class provides the foundation, while specialized traits offer functionality for database management, controller testing, and feature testing, allowing for clean, maintainable, and effective tests.
Sources: source/testing/overview.rst:3-11, source/testing/index.rst:3-5
Core Testing Infrastructure
At the heart of CodeIgniter's testing capabilities is the CodeIgniter\Test\CIUnitTestCase class. It sets up a minimal environment for running tests and should be the parent class for all application test cases. To facilitate different types of testing, several traits are provided that can be included in your test classes.
Sources: source/testing/overview.rst:13-19
Key Testing Traits
| Trait | Description | Source File |
|---|---|---|
DatabaseTestTrait | Provides tools to test database interactions, including migrating, seeding, and transaction management within a test environment. | source/testing/database.rst |
ControllerTestTrait | Allows you to test your controllers without running a full HTTP request, enabling focused testing of controller logic and responses. | source/testing/controllers.rst |
FeatureTestTrait | Enables "feature tests" that simulate full HTTP requests to your application and allow you to assert against the entire response. | source/testing/feature.rst |
StreamFilterTrait | A helper trait used to capture output sent to php://stdout and php://stderr, useful for testing CLI commands and other output. | source/testing/overview.rst |
Sources: source/testing/overview.rst:21-31
The following diagram illustrates the relationship between a user's test case and the core testing components.
This diagram shows a sample test class MyControllerTest inheriting from CIUnitTestCase and utilizing the DatabaseTestTrait and ControllerTestTrait for specific testing functionalities.
Sources: source/testing/overview.rst:13-15, source/testing/database.rst:16-17, source/testing/controllers.rst:15-16
Database Testing
The DatabaseTestTrait provides essential functionality for testing code that interacts with a database. It ensures a clean testing environment by managing schema migrations, data seeding, and database state between tests.
Sources: source/testing/database.rst:3-5
Key Features
- Database Group: By default, tests run on an in-memory SQLite3 database for speed. You can change the database group by setting the
$DBGroupproperty in your test class. - Migrations and Seeding: The trait can automatically run your database migrations and/or seeds before each test. This is controlled by the
$migrate,$migrateOnce,$seed, and$seedOnceproperties. - Transaction Rollbacks: Each test method is wrapped in a database transaction that is rolled back at the end, isolating tests from each other. This can be disabled by setting
$refreshtofalse.
Sources: source/testing/database.rst:24-26, source/testing/database.rst:43-58, source/testing/database.rst:37-39
The typical lifecycle of a database test using this trait is as follows:
This flow demonstrates how the DatabaseTestTrait prepares the database, runs the test, and then cleans up, ensuring test isolation.
Sources: source/testing/database.rst:37-58
Example Usage
To use the trait, include it in your test class and set the appropriate properties.
<?php
namespace App\Controllers;
use CodeIgniter\Test\CIUnitTestCase;
use CodeIgniter\Test\DatabaseTestTrait;
class MyTests extends CIUnitTestCase
{
use DatabaseTestTrait;
// For Migrations
protected $migrate = true;
protected $migrateOnce = false;
protected $namespace = 'App';
// For Seeds
protected $seed = 'TestSeeder';
protected $seedOnce = false;
protected $basePath = APPPATH . 'Database';
public function testSomething()
{
// ...
}
}
Sources: source/testing/database.rst:15-35, source/testing/database.rst:51-66
Controller Testing
The ControllerTestTrait allows for testing controllers in isolation, without the overhead of a full HTTP request. You can specify the request method, URI, body, headers, and spoofed session data, then execute a controller method and assert against the result.
Sources: source/testing/controllers.rst:3-10
Simulating a Request
The trait provides a fluent interface for building the request that will be sent to the controller.
$result = $this->withURI('http://example.com/users')
->withBody(['name' => 'John', 'email' => 'john@example.com'])
->withHeaders(['X-API-KEY' => 'secret'])
->controller(UserController::class)
->execute('createUser');
This example demonstrates chaining methods to set the URI, body, and headers before specifying the controller and the method to execute (createUser).
Sources: source/testing/controllers.rst:22-45
The following sequence diagram illustrates the process of a controller test.
This diagram shows the test method configuring the request via the trait, which then instantiates and executes the specified controller method, returning a TestResponse object for assertions.
Sources: source/testing/controllers.rst:15-45
Feature Testing
Feature tests, enabled by FeatureTestTrait, are a more powerful way to test your application by simulating a full HTTP request. Unlike controller tests, they engage the entire framework stack, including routing, filters, and the complete response generation. This makes them ideal for testing API endpoints or the interaction of multiple components.
Sources: source/testing/feature.rst:3-10
Making Calls
You can simulate requests using the call() method, which accepts the HTTP method and the path to test.
// Simple GET request
$result = $this->call('get', 'users');
// POST request with parameters
$result = $this->call('post', 'users', [
'name' => 'John',
'email' => 'john@example.com',
]);
The call() method returns a TestResponse object, which can then be used for various assertions.
Sources: source/testing/feature.rst:22-31
Feature Test Flow
This flowchart shows the steps involved in a feature test, from the initial call() to routing, filter execution, controller action, and finally returning a response for assertion.
Sources: source/testing/feature.rst:3-10
Response Assertions
Both controller and feature tests return a CodeIgniter\Test\TestResponse object, which provides a rich set of assertion methods to verify the outcome of the request. These assertions are built on top of PHPUnit's assertion library.
Sources: source/testing/response.rst:3-6
Common Assertions
| Method | Description |
|---|---|
isOK() | Asserts that the response has a status code in the 200 or 300 range. |
isRedirect() | Asserts that the response is a redirect. |
assertStatus(int $code) | Asserts a specific HTTP status code. |
assertHeader(string $key) | Asserts that a specific header exists in the response. |
see(string $text) | Asserts that the given text is found in the response body. |
seeJSON(string $json) | Asserts that the response body is a JSON fragment matching the given one. |
assertJSONFragment(...) | Asserts that a JSON response contains a specific fragment/value. |
assertSessionHas(...) | Asserts that a value exists in the session. |
Sources: source/testing/response.rst:21-150
Example of Assertions
public function testUserCreation()
{
$result = $this->call('post', 'users', [
'name' => 'John',
'email' => 'john@example.com',
]);
$result->assertStatus(201);
$result->assertRedirect();
$result->assertSessionHas('message', 'User created successfully');
}
This example shows a feature test that posts data to create a user and then asserts the response status code, checks for a redirect, and verifies a session flash message.
Sources: source/testing/feature.rst:22-31, source/testing/response.rst:30-32, source/testing/response.rst:41-43, source/testing/response.rst:133-135
Conclusion
The testing suite in CodeIgniter 4 is a powerful and integral part of the framework. By leveraging CIUnitTestCase and the specialized DatabaseTestTrait, ControllerTestTrait, and FeatureTestTrait, developers can write clean, expressive, and comprehensive tests. This ensures application reliability, simplifies refactoring, and promotes a high standard of code quality. The built-in response assertions further streamline the process of verifying application behavior from the database layer all the way to the final HTTP response.
Sources: source/testing/index.rst:3-5, source/testing/overview.rst:3-5