This is based on Laravel 5.5.
The phpUnit documentation is at https://phpunit.de/manual/current/en/index.html
create
# Create a test case
php artisan make:test XXControllerTest
# Create a unit test
php artisan make:test XXUnitTest --unit
usage
HTTP
- json
- get
- post
- put
- delete
ex:
public function testHttpSample()
{
array $json = [];
$this->json("PUT", $url, $json)
->assertExactJson(['errno' => 0]);
}
Database
The database section is very detailed in the official documentation. The main assertions check whether a certain entry exists in the database, whether it doesn’t exist, and soft delete checks.
public function testDbSample()
{
$this->assertDatabaseHas('sample_table', [
'id' => '100',
'data' => 'sample'
]);
}
Mocking
The official documentation only provides a few examples in this section. In practical applications, I have more useful usages, such as the Log object:
public function testLogSample
{
// This method can be used to simulate that after an error is triggered,
// the error log printed in the code matches expectations,
// and from this we can infer whether the expected error was triggered
Log::shouldRecive('error')->once()->with('error happened');
// run test...
// ...
}
Guzzle
Guzzle, as an important module for making HTTP sub-requests, should also be covered by test cases in Laravel. Guzzle provides its own Mock method:
public function testGuzzleSample
{
$mockResponses = [
[
200, // code
['Content-Type' => 'application/json'], // headers
'{"errno": 0}' // body
]
[
500, // code
['Content-Type' => 'application/json'], // headers
'{"errno": 99}' // body
]
];
$mockHandler = new Client([
'handler' => HandlerStack::create(
(new MockHandler($mockResponses))
)
]);
$this->app->instance('GuzzleHttp\Client', $mockHandler);
// run tests...
// ...
// During testing, guzzle will return the predefined responses in order to test expected cases.
}
Extended usage: To specifically test the input and output of sub-requests, you can write a simple MVC class that takes the expected sub-request input (url, method, header, body) to dynamically generate the $mockResponses array in the example.
env
In the Laravel project directory, there’s a phpunit.xml file where you can specify some environment variables to be used during test runs.
<?xml version="1.0" encoding="UTF-8"?>
<phpunit backupGlobals="false"
backupStaticAttributes="false"
bootstrap="bootstrap/autoload.php"
colors="true"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
processIsolation="false"
stopOnFailure="false">
<testsuites>
<testsuite name="Feature">
<directory suffix="Test.php">./tests/Feature</directory>
</testsuite>
<testsuite name="Unit">
<directory suffix="Test.php">./tests/Unit</directory>
</testsuite>
</testsuites>
<filter>
<whitelist processUncoveredFilesFromWhitelist="true">
<directory suffix=".php">./app</directory>
</whitelist>
</filter>
<php>
<env name="APP_ENV" value="testing"/>
<env name="CACHE_DRIVER" value="array"/>
<env name="SESSION_DRIVER" value="array"/>
<env name="QUEUE_DRIVER" value="sync"/>
<env name="DB_HOST" value="127.0.0.1"/>
<env name="DB_PORT" value="3306"/>
<env name="DB_DATABASE" value="lavaral_test"/>
</php>
</phpunit>
I forced the specification of the database address and name used during testing in the project to prevent someone from running this script in production with the .env file settings and operating on the production database.
Of course, the official configuration documentation mentions that during test runs, if a .env.testing file exists, when using the --env=testing parameter, .env.testing will override the .env file.
run
Running test cases is very simple - just execute the phpunit file in the project directory.
./vendor/bin/phpunit
phpunit also has some options available. The one I mainly use is --filter, to execute a specific test case or batch of test cases.
./vendor/bin/phpunit --filter=testHttp