Testing WordPress
COQUARD Cyrille
24/04/2024
What is testing?
COQUARD Cyrille
- Stands for automated tests
- Code to assert application behavior
- Multiple type of tests
24/04/2024
Effective testing is hard
COQUARD Cyrille
- Know why testing
- Know what to test
- Know how to test
- Know when to test
Bad test
=
Useless
24/04/2024
Effective testing is high reward
COQUARD Cyrille
Tests are your copilot
- Low number of bugs
- Delivering on time
- Prevent over engineering
24/04/2024
Unit
vs
Integration
COQUARD Cyrille
24/04/2024
Unit vs Integration:
The academic way
COQUARD Cyrille
Unit
- Class or method level
- More isolated
- Developper oriented
- Easy to setup
- First ones to learn
Integration
- Feature level
- More abstract
- Business oriented
- Complex to setup
24/04/2024
Unit vs Integration:
The academic way
COQUARD Cyrille
What is the issue?
24/04/2024
Unit vs Integration:
The academic way
COQUARD Cyrille
We ain't at school
- CEO / Manager decides
- Rentability / on schedule is key
24/04/2024
Unit vs Integration:
The real world way
COQUARD Cyrille
Unit
- More fragile so low productivity
- Developper language
- Lot of tests
- Need to create testcases
Integration
- More abstract so high productivity
- Business language
- Reduced number of tests
- Based on project definition
24/04/2024
Unit vs Integration:
Start with integration
COQUARD Cyrille
Integration
- Higher productivity
- Business language (transparency)
- Reduced number of tests
- Ensure the feature is done
24/04/2024
Unit vs Integration:
Start with integration
COQUARD Cyrille
Unit
- Integration test not possible
- Still provides coverage
- Ensure code is working
- Can't ensure the feature is done
24/04/2024
How to test
COQUARD Cyrille
24/04/2024
How to test:
Setup the environnement
COQUARD Cyrille
- Setup a development env: wordpress/env
- Setup integration tests: wp-media/phpunit
- Ease filter mocking: wp-launchpad/phpunit-wp-hooks
- Create the base for integration tests
24/04/2024
How to test:
Create tests
COQUARD Cyrille
Now what?
24/04/2024
How to test:
What to test?
COQUARD Cyrille
Assert you made the job not work done
- Testing your code: Useless
- Testing expectations: Useful
24/04/2024
How to test:
What to test ?
COQUARD Cyrille
Test Driven Development
- Really trendy
- Really dogmatic
- Better done than perfect
24/04/2024
How to test:
What to test ?
COQUARD Cyrille
Rome didn't built in one day
- Learn gradually
- TDD doctrines won't be followed strictly
- You need to understand
24/04/2024
How to test:
What to test ?
COQUARD Cyrille
Most important in TDD
- Write test before code: Keep candid mind
- Make sure they fail before writing code: Useful code
- Make sure all tests pass when writing code: Assert task done
24/04/2024
How to test:
What to test ?
COQUARD Cyrille
The utopy
- Nice on paper
- Issue is apply IRL
Issues
- How to select the simplest test?
- What is the quickest code?
24/04/2024
How to test:
Select simple test
COQUARD Cyrille
Acceptance criteria
- Simple sentence asserting a behavior
- Done by the person scoping the project
- Ensure you are not testing your code
24/04/2024
How to test:
Select simple test
COQUARD Cyrille
What it is not
- A video
- A block of text
- Code
- Image is preloaded using the image URLs
from srcset attribute and becomes imagesrcset
- sizes="50vw" attribute is moved to the
preload markup and becomes imagesizes="50vw"
- fetchpriority="high" is added to the
preload markup
- Image is excluded from LL feature
24/04/2024
How to test:
Gerkhin
COQUARD Cyrille
AAA
- Arrange=Given
- Act=When
- Assert=Then
GIVEN image with srcset "http://my-image.example/img.png"
WHEN the image is preloaded
THEN image have imagesrcset "http://my-image.example/img.png"
AND no srcset
GIVEN image with sizes "50vw"
WHEN the image is preloaded
THEN image have imagesizes "50vw"
AND no sizes
GIVEN an image
WHEN the image is preloaded
THEN image have fetchpriority "high"
GIVEN an image
WHEN the image is preloaded
THEN image is excluded from lazyload
24/04/2024
How to test:
Build around Acceptance criteria
COQUARD Cyrille
Find limits
- Failing HTTP request
- Issue while inserting DB
GIVEN image with srcset "http://my-image.example/img.png"
WHEN the image is preloaded
THEN image have imagesrcset "http://my-image.example/img.png"
AND no srcset
GIVEN image with sizes "50vw"
WHEN the image is preloaded
THEN image have imagesizes "50vw"
AND no sizes
GIVEN an image
WHEN the image is preloaded
THEN image have fetchpriority "high"
GIVEN an image
WHEN the image is preloaded
THEN image is excluded from lazyload
24/04/2024
How to test:
Structure a test
COQUARD Cyrille
AAA
- Arrange: put the plugin in a certain state
- Act: run the logic to test
- Assert: verify the plugin is in the expected state
<?php
class Test_Logout extends TestCase {
public function testLogoutShouldNotEdit()
{
do_action(
'grant_admin',
wp_current_user()
);
do_action('logout');
$this->assertSame(
false,
apply_filters(
'user_can_edit',
false
)
);
}
}
24/04/2024
How to test:
Find the quickest code
COQUARD Cyrille
Cheating is ok
- You are testing on fixed data
- What matters is the final output
Make baby steps
- Checking one condition
- You can edit previous tests
24/04/2024
Usual testing scenarios
COQUARD Cyrille
24/04/2024
How to test:
Adapt to usual cases
COQUARD Cyrille
Scenarios
- Unleash CQRS power
- Control filter value
- Mock external API
- Isolate callback
24/04/2024
How to test:
Unleash CQRS power
COQUARD Cyrille
Problem
Need to re-implement a way to interact with the element for each test
Solution
Use action and filter to cut your logic into small units
24/04/2024
How to test:
Unleash CQRS power
COQUARD Cyrille
Solution
Use action and filter to cut your logic into small units
<?php
class Test_Logout extends TestCase {
public function testLogoutShouldNotEdit()
{
do_action(
'grant_admin',
wp_current_user()
);
do_action('logout');
$this->assertSame(
false,
apply_filters(
'user_can_edit',
false
)
);
}
}
24/04/2024
How to test:
Control filter value
COQUARD Cyrille
Problem
Need control flow to direct the test into a certain state
Solution
Mock the filter with a callback function
24/04/2024
How to test:
Control filter value
COQUARD Cyrille
Solution
Mock the filter with a callback function
<?php
class Test_Logout extends TestCase {
public function testLogoutShouldNotEdit()
{
...
}
/**
* @hook my_filter 10
*/
public function my_callback() {
return true;
}
}
24/04/2024
How to test:
Mock external API
COQUARD Cyrille
Problem
The code call an external API and there is no control about it
Solution
Use wp_remote_request and mock the filter with a callback function
24/04/2024
How to test:
Mock external API
COQUARD Cyrille
Solution
Use wp_remote_request and mock the filter with a callback function
<?php
class Test_Logout extends TestCase {
public function testLogoutShouldNotEdit()
{
...
}
/**
* @hook pre_http_request 10
*/
public function my_callback($response, $args, $url) {
if (
strpos(
$url,
'https://app.imagify.io' ) === false
) {
return $response;
}
return [
'body' => $message,
'response' => ['code' => 200 ]
];
}
}
24/04/2024
How to test:
Isolate callback
COQUARD Cyrille
Problem
The callback to test is linked to an hook with lot of callbacks making lot of noise
Solution
Isolate the callback by removing all other callbacks
24/04/2024
How to test:
Isolate callback
COQUARD Cyrille
Solution
Isolate the callback by removing all other callbacks
<?php
class Test_Logout extends TestCase {
/**
* @isolate-hook my-event myCallback 15
**/
public function testLogoutShouldNotEdit()
{
// ...
}
}
24/04/2024
Any question?
COQUARD Cyrille
24/04/2024
Time for an example
COQUARD Cyrille
24/04/2024
Time for an example
The context
COQUARD Cyrille
Objectives
- Add result to API
- Save into DB
- Add a job to queue
24/04/2024
Time for an example
The context
COQUARD Cyrille
Objectives
- Fetch result from API
- Save into DB
24/04/2024
Time for an example
The context
COQUARD Cyrille
Acceptance criterion
-
GIVEN no tracking row WHEN job added to Sauron THEN tracking job should be pending AND a job should be created to check result
-
GIVEN tracking row WHEN job added to Sauron THEN tracking job should be updated to pending AND a job should be created to check result
24/04/2024
Time for an example
The context
COQUARD Cyrille
Acceptance criterion
-
GIVEN no tracking row WHEN job fails to be added to Sauron THEN tracking job should be failed AND no job should be created to check result
24/04/2024
Time for an example
The context
COQUARD Cyrille
Complete cases:
-
Fail add API:
-
5xx
-
4xx
-
-
Fail add db
24/04/2024
Time for an example
The context
COQUARD Cyrille
Acceptance criterion
-
GIVEN no tracking row and no job WHEN job fetched from Sauron THEN tracking job should be failed
-
GIVEN tracking row and no job WHEN job fetch from Sauron THEN tracking job should be updated to failed
24/04/2024
Time for an example
The context
COQUARD Cyrille
Acceptance criterion
-
GIVEN no tracking row and job pending WHEN job fetched from Sauron THEN tracking job should be pending and a new job should be created
24/04/2024
Time for practice
COQUARD Cyrille
24/04/2024
Testing WordPress
By Cyrille Coquard
Testing WordPress
- 113