The session "Testing in Laravel" briefly describes
- Why should we write automated test
- What to test in a Laravel app
- Unit vs Functional testing
- Preparing environment for testing
- Preparing database for testing
- Various assertions available in TestResponse of Laravel
- Test execution lifecycle
- Running filtered set of tests
5. Why Automated Testing?
Doesn’t it waste valuable developer time?
• Reduces the time and cost of testing
• Increases the accuracy of testing
• Improves the quality of software
• Con
fi
dence of changing anytime
7. What to test?
Code Coverage? (how many codes are tested)
https://medium.com/@anowarhossain/code-coverage-report-in-laravel-and-make-100-coverage-of-your-code-ce27cccbc738
8. What to test?
Things that … you want to ensure “NOT BROKEN”
https://laraveldaily.com/post/matt-stau
ff
er-laravel-enterprise-ready
9. What to test?
The essential things…
• The routes - main entry points
• Authentication and authorisations
• Thing related to payment / privacy / legal issues
• Business decisions
• Third party dependencies (with mock or stub)
• Anything that have de
fi
ned expectations
Anything that you’d like to con
fi
rm after a new deployment
12. Unit Testing vs Functional Testing
Unit Testing Functional Testing
Scope Individual units of code Overall functionality of a software
Target Speci
fi
c values, conditions, returns, exceptions Ensure features and requirements
Frequency Every time any relevant code changes Every time any dependency/expectation changes
Perspective Whitebox. (Transparent) Blackbox. (Machine with opaque casing)
18. Preparing Environment
Options to de
fi
ne separate con
fi
guration
<php>
<env name="APP_ENV" value="testing"/>
<env name="BCRYPT_ROUNDS" value="4"/>
<env name="CACHE_DRIVER" value="array"/>
<env name="DB_CONNECTION" value="sqlite"/>
<env name="DB_DATABASE" value=":memory:"/>
<env name="MAIL_MAILER" value="array"/>
<env name="QUEUE_CONNECTION" value="sync"/>
<env name="SESSION_DRIVER" value="array"/>
<env name="TELESCOPE_ENABLED" value=“false"/>
</php>
phpunit.xml
19. Preparing Environment
Options to de
fi
ne separate con
fi
guration
<php>
<env name="APP_ENV" value="testing"/>
<env name="BCRYPT_ROUNDS" value="4"/>
<env name="CACHE_DRIVER" value="array"/>
<env name="DB_CONNECTION" value="sqlite"/>
<env name="DB_DATABASE" value=":memory:"/>
<env name="MAIL_MAILER" value="array"/>
<env name="QUEUE_CONNECTION" value="sync"/>
<env name="SESSION_DRIVER" value="array"/>
<env name="TELESCOPE_ENABLED" value="false"/>
</php>
MAIL_MAILER=smtp
MAIL_HOST=mailhog
MAIL_PORT=1025
.env.testing
phpunit.xml
20. Preparing Database
Isolated and risk free version - for testing environment
<php>
...
<env name="DB_CONNECTION" value="sqlite"/>
<env name="DB_DATABASE" value=":memory:"/>
...
</php>
phpunit.xml
21. Preparing Database
Cleanup and prepare for testing new scenario
use IlluminateFoundationTestingDatabaseMigrations;
use IlluminateFoundationTestingRefreshDatabase;
use TestsTestCase;
class HomepageTest extends TestCase
{
use DatabaseMigrations, RefreshDatabase;
public function test_something_with_predefined_data()
{
// Run the DatabaseSeeder...
$this->seed();
// Run an array of specific seeders...
$this->seed([
AreaListSeeder::class,
DocumentCategoriesSeeder::class,
]);
}
// ...
Execute Migrations before running test
Cleanup DB after running test
Stage a prede
fi
ned scenario in DB
23. What can we Assert?
Various points to validate application sanity
Look into Testing/TestResponse
24. Check if
expected text
is showing in
page
$response = $this->actingAs($user)->get('/path');
// Find text in response page
$response->assertSee('Dashboard');
$response->assertDontSee('Admin');
// Can be used array of text, also can verify in order
$response->assertSee(['A Menu Item', 'Another Menu Item’]);
// Also can verify if they are showing in order
$response->assertSeeInOrder(['A Menu Item', 'Another Menu Item']);
// All of the above has a *Text() alternative
// that strip_tags the response before compare
$response->assertSeeText('Dashboard');
25. What was
passed to
the view?
public function test_it_has_the_correct_value()
{
$response = $this->get('/some-route');
$this->assertEquals('John Doe', $response->viewData('name'));
}
public function test_it_contains_a_given_record()
{
$response = $this->get('/some-route');
$this->assertTrue($response->viewData('users')->contains($userA));
}
public function test_it_returns_the_correct_amount_of_records()
{
$response = $this->get('/some-route');
$this->assertCount(10, $response->viewData('users'));
}
Code snippet source
27. Validating
Database
records
$user = User::factory()->create();
// Check model existence
$this->assertModelExists($user);
$this->assertModelMissing($user);
// SoftDeleted or not
$this->assertSoftDeleted($user);
$this->assertNotSoftDeleted($user);
// Count records
$this->assertDatabaseCount('users', 5);
// Check specific record
$this->assertDatabaseHas('users', [
'email' => 'sally@example.com',
]);
28. Exception
Handling
// In feature testing
$response = $this->withoutExceptionHandling()->get('/');
// Mention which exception is expected
$this->expectException(MyAccessParsingException::class);
29. Filtering Test
Run speci
fi
c set of tests
php artisan test
// Run Specific TestSuite
php artisan test --testsuite Unit
// Run a single class
php artisan test --filter=HomepageTest
// Run a single function
php artisan test --filter=test_home_responds_with_success_for_Admin