Unit Test In Laravel
By: Ahmed Yahia
ayahiacs@gmail.com
ahmed.mahmoud@ibtikar.net.sa
2
Why unit testing?
☐ Agile process (Refactoring confidently)
☐ Code Quality:
– makes you think harder about the problem.
– exposes the edge cases.
☐ Finding Bugs Early (feature doesn't fail because of low level code)
☐ It is a very good Documentation.
☐ Debugging.
☐ Design (testing a unit makes you know its responsibility).
☐ Reduce Costs (Finding Bugs Early)
3
Unit testing focus on low level modules (functions)
Inside every well-written large program is a well-written small
program.
-- Charles Antony Richard Hoare, computer scientist
4
E.g. Number of open connections per IP
netstat -ntu | awk '{print $5}' | cut -d: -f1 | sort | uniq -c | sort -n
5
Unit Test In Laravel
phpunit already exist
– Phpunit is an old and common a php testing package
`Tests` folder already exist with subfolders `Feature`, `Unit`
6
Unit Test In Laravel
Configuration:
– use phpunit.xml file
● to set testing env variables (remember to run config:clear)
– in addition you can add file .env.testing to overwrite .env before running test
7
Unit Test In Laravel
Creation:
– php artisan make:test UserTest
● Create a test in the Feature directory…
– php artisan make:test UserTest –unit
● Create a test in the Unit directory...
●
8
Unit Test In Laravel
The test case:
If you define your own setUp / tearDown methods in a test class, be sure to call
parent::setUp() / parent::tearDown() methods.
9
Laravel HTTP Testing
withHeaders
$response = $this->withHeaders([
'X-Header' => 'Value',
])->json('POST', '/user', ['name' => 'Sally']);
10
Laravel HTTP Testing
withSession
$response = $this->withSession(['foo' => 'bar'])
->get('/');
11
Laravel HTTP Testing
actingAs
$user = factory(User::class)->create();
$response = $this->actingAs($user)
->withSession(['foo' => 'bar'])
->get('/');
12
Laravel HTTP Testing
json testing:
assertJson (contains keys and values):
AssertExactJson (contains ONLY the keys and values):
...->assertExactJson
$response = $this->json('POST', '/user', ['name' => 'Sally']);
$response
->assertStatus(201)
->assertJson([
'created' => true,
]);
13
Upload Testing
public function testAvatarUpload()
{
Storage::fake('avatars'); //fake disk
$file = UploadedFile::fake()->image('avatar.jpg');
$response = $this->json('POST', '/avatar', [
'avatar' => $file,
]);
// Assert the file was stored...
Storage::disk('avatars')->assertExists($file->hashName());
// Assert a file does not exist...
Storage::disk('avatars')->assertMissing('missing.jpg');
}
14
Assertions available
assertCookie
assertCookieExpired
assertCookieNotExpired
assertCookieMissing
assertDontSee
assertDontSeeText
assertExactJson
assertForbidden
assertHeader
assertHeaderMissing
assertJson
assertJsonCount
assertJsonFragment
assertJsonMissing
assertSeeTextInOrder
assertSessionHas
assertSessionHasAll
assertSessionHasErrors
assertSessionHasErrorsIn
assertSessionHasNoErrors
assertSessionDoesntHaveErrors
assertSessionMissing
assertStatus
assertSuccessful
assertViewHas
assertViewHasAll
assertViewIs
assertViewMissing
assertJsonMissingExact
assertJsonMissingValidationErrors
assertJsonStructure
assertJsonValidationErrors
assertLocation
assertNotFound
assertOk
assertPlainCookie
assertRedirect
assertSee
assertSeeInOrder
assertSeeText
assertSeeTextInOrder
15
Dusk (Browser Test)
Started from Laravel version >= 5.4
16
Dusk
Installation:
composer require --dev laravel/dusk
php artisan dusk:install
17
Dusk
configuration:
☐ .env.dusk.local (to overwrite .env while testing)
☐ APP_URL (env varaible must be set)
18
Dusk
Run tests:
☐ php artisan dusk
19
Dusk - usage
$this->browse(function ($browser) use ($user) {
$browser->visit('/login')
->type('email', $user->email)
->type('password', 'secret')
->press('Login')
->assertPathIs('/home');
});
20
Dusk Browser InterAction methods
clickLink
value
text
attribute
keys
type
append
clear
select
dragDown
dragLeft
dragRight
dragOffset
acceptDialog
typeInDialog
dismissDialog
radio
check
uncheck
attach
press
pressAndWaitFor
script
Drag
dragUp
21
Dusk Browser Assertion methods
assertTitle
assertTitleContains
assertUrlIs
assertPathIs
assertPathBeginsWith
assertPathIsNot
assertFragmentIs
assertFragmentBeginsWith
assertFragmentIsNot
assertRouteIs
assertQueryStringHas
assertQueryStringMissing
assertHasCookie
assertCookieMissing
assertRadioSelected
assertRadioNotSelected
assertSelected
assertNotSelected
assertSelectHasOptions
assertSelectMissingOptions
assertSelectHasOption
assertSelectMissingOption
assertValue
assertVisible
assertPresent
assertMissing
assertDialogOpened
assertCookieValue
assertPlainCookieValue
assertSourceHas
assertSourceMissing
assertSee
assertDontSee
assertSeeIn
assertDontSeeIn
assertSeeLink
assertDontSeeLink
assertInputValue
assertInputValueIsNot
assertChecked
assertNotChecked
22
Database testing
Factories
$users = factory(AppUser::class, 3)
->create()
->each(function ($user) {
$user->posts()->save(factory(AppPost::class)->make());
});
23
Database testing
use RefreshDatabase;
● reset database after each test.
● data from a previous test does not interfere
with subsequent tests.
● The RefreshDatabase trait takes the most
optimal approach to migrating your test
database depending on if you are using an in-
memory database or a traditional database.
24
Assertions
$this->assertDatabaseHas($table, array $data);
$this->assertDatabaseMissing($table, array $data);
$this->assertSoftDeleted($table, array $data);
25
TDD
simple functions names makes it easy to start from test case
Each test case has a 3 As (AAA)
Arrange, Act, Assert
26
TDD - Example User Story
scenario 1:
Given
When notes list pages loaded
Then I should see 'notes list'
and my notes added
as a user I would like to view list of my notes:
acceptance criteria:
27
TDD - Example User Story
as a user I would like to add new notes:
scenario 1:
Given -
When I type note shorter that 5 letters and press add
Then I should still in add note page and see validation error
scenario 2:
Given note "note1" already existed
When I type note "note1" again and press add
Then I should still in add note page and see already exist error
28
TDD – convert scenario to test case
scenario 1:
Given -
When I type note shorter that 5 letters and press add
Then I should still in add note page and see validation error
$this->browse(function ($browser) use ($user) {
$browser->visit('/notes/create')
->type('note', '1234')
->press('add')
->assertPathIs('/notes/create')
->assertSee('invalid')
});
Would
be
29
TDD
Then loop until the test case passes
–
Php artisan dusk
Fix the error
30
How Deep Should I Unit test
I get paid for code that works, not for tests, so my
philosophy is to test as little as possible to reach a given
level of confidence
– Kent Beck
https://www.pixelstech.net/article/1346685066-How-deep-sho
Thank You
By: Ahmed Yahia
ayahiacs@gmail.com
ahmed.mahmoud@ibtikar.net.sa

Testing in Laravel