{"id":161,"date":"2022-05-01T22:21:00","date_gmt":"2022-05-01T22:21:00","guid":{"rendered":"https:\/\/www.mitango.app\/?p=161"},"modified":"2024-11-11T22:35:44","modified_gmt":"2024-11-11T22:35:44","slug":"create-unit-tests-for-wordpress-plugin","status":"publish","type":"post","link":"https:\/\/www.mitango.app\/fr\/2022\/05\/01\/create-unit-tests-for-wordpress-plugin\/","title":{"rendered":"Create Unit tests for WordPress Plugin"},"content":{"rendered":"<p><a href=\"https:\/\/medium.com\/@crochetfeve0251?source=post_page---byline--376e82a0df92--------------------------------\" target=\"_blank\" rel=\"noopener\"><\/a><\/p>\n\n\n\n<p id=\"22ce\">Automated tests are the base of modern programming development process and are as important as the architecture from the code itself.<\/p>\n\n\n\n<p id=\"db1b\">As they are what prevent regression in your project preventing your project to crumble on itself.<\/p>\n\n\n\n<p id=\"8113\">In this article, we will focus more particularly on unit test.<\/p>\n\n\n\n<p id=\"00ea\">The main objective from an unit test is to make sure everything is working well inside a class due to this our tests will always focus on one class.<\/p>\n\n\n\n<p id=\"b0b4\">For this we will use the most used PHP test library&nbsp;<a href=\"https:\/\/phpunit.de\/\" rel=\"noreferrer noopener\" target=\"_blank\"><strong>PHPUnit<\/strong><\/a>&nbsp;but other libraries exists and tools we will use in this article adapt to most of the frameworks.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"c97c\">Configure PHPUnit<\/h2>\n\n\n\n<p id=\"1d87\">The first step when creating unit tests is to install our environment.<\/p>\n\n\n\n<p id=\"a5d3\">For that we will first to create a\u00a0<a href=\"https:\/\/getcomposer.org\/\" target=\"_blank\" rel=\"noreferrer noopener nofollow\"><strong>Composer<\/strong><\/a>\u00a0project if this is not done.<\/p>\n\n\n\n<p id=\"3017\">On Ubuntu, we can install\u00a0<a href=\"https:\/\/getcomposer.org\/\" target=\"_blank\" rel=\"noreferrer noopener nofollow\"><strong>Composer<\/strong><\/a>\u00a0with the following command:<\/p>\n\n\n\n<pre class=\"wp-block-code is-style-light\"><code>sudo apt install composer<\/code><\/pre>\n\n\n\n<p id=\"375d\">Once this is done, you can move to the project folder (plugin or theme folder) and run this command to create the&nbsp;<a href=\"https:\/\/getcomposer.org\/\" rel=\"noreferrer noopener\" target=\"_blank\"><strong>Composer<\/strong><\/a>&nbsp;project:<\/p>\n\n\n\n<pre class=\"wp-block-code is-style-light\"><code>composer init<\/code><\/pre>\n\n\n\n<p id=\"7b4b\">Once this is done a file called&nbsp;<strong><em>composer.json<\/em><\/strong>&nbsp;should have been created.<\/p>\n\n\n\n<p id=\"b6ed\">If so we can start to add&nbsp;<a href=\"https:\/\/phpunit.de\/\" rel=\"noreferrer noopener\" target=\"_blank\"><strong>PHPUnit<\/strong><\/a>&nbsp;to the project with the following command:<\/p>\n\n\n\n<pre class=\"wp-block-code is-style-light\"><code>composer require --dev phpunit\/phpunit<\/code><\/pre>\n\n\n\n<p id=\"96b1\">Then we can install the project with the following command:<\/p>\n\n\n\n<pre class=\"wp-block-code is-style-light\"><code>composer install<\/code><\/pre>\n\n\n\n<p id=\"c821\">Once this step is done a new file called&nbsp;<strong><em>composer.lock<\/em><\/strong>&nbsp;and a&nbsp;<strong><em>vendor<\/em><\/strong>&nbsp;folder should have been created.<\/p>\n\n\n\n<p id=\"639a\">At this level\u00a0<a href=\"https:\/\/phpunit.de\/\" target=\"_blank\" rel=\"noreferrer noopener nofollow\"><strong>PHPUnit<\/strong><\/a>\u00a0is installed but not configured into your project.<\/p>\n\n\n\n<p id=\"b995\">For that, we will first create a folder\u00a0<strong><em>tests<\/em><\/strong>\u00a0that we will fill with the files used to create tests and configure\u00a0<a href=\"https:\/\/phpunit.de\/\" target=\"_blank\" rel=\"noreferrer noopener nofollow\"><strong>PHPUnit<\/strong><\/a>.<\/p>\n\n\n\n<p id=\"9695\">In that folder&nbsp;<strong><em>tests<\/em><\/strong>&nbsp;we will create another folder&nbsp;<strong><em>Unit<\/em><\/strong>&nbsp;that will be used for our unit tests. This is not mandatory but it will organize your tests better as there is not only unit tests and it is more practical to separate them.<\/p>\n\n\n\n<p id=\"89f0\">In that folder we will have to create 3 files to configure\u00a0<a href=\"https:\/\/phpunit.de\/\" target=\"_blank\" rel=\"noreferrer noopener nofollow\"><strong>PHPUnit<\/strong><\/a>:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong><em>TestCase.php<\/em><\/strong>: The base class for all of your test classes.<\/li>\n\n\n\n<li><strong><em>bootstrap.php<\/em><\/strong>: This file will load every resource necessary for the tests.<\/li>\n\n\n\n<li><strong><em>phpunit.xml.dist<\/em><\/strong>: Configuration file from\u00a0<a href=\"https:\/\/phpunit.de\/\" target=\"_blank\" rel=\"noreferrer noopener nofollow\"><strong>PHPUnit<\/strong><\/a><strong>.<\/strong><\/li>\n<\/ul>\n\n\n\n<p id=\"042c\">We will start by creating the\u00a0<strong><em>TestCase.php<\/em><\/strong>\u00a0file where we will add this content to extend our cases from\u00a0<a href=\"https:\/\/phpunit.de\/\" target=\"_blank\" rel=\"noreferrer noopener nofollow\"><strong>PHPUnit<\/strong><\/a>\u00a0TestCase class:<\/p>\n\n\n\n<pre class=\"wp-block-code is-style-light\"><code>&lt;?php<br><br><br>use PHPUnit\\Framework\\TestCase as BaseTestCase;<br><br>abstract class TestCase extends BaseTestCase<br>{<br>    <br>}<\/code><\/pre>\n\n\n\n<p id=\"eddf\">Then we will write the following content into&nbsp;<strong><em>bootstrap.php&nbsp;<\/em><\/strong>to load our code and the base TestCase:<\/p>\n\n\n\n<pre class=\"wp-block-code is-style-light\"><code>&lt;?php<br>require_once dirname(<em>__DIR__<\/em>) . '\/..\/vendor\/autoload.php';<br><br>require_once <em>__DIR__ <\/em>. '\/TestCase.php';<\/code><\/pre>\n\n\n\n<p id=\"ec89\">Finally we add to configure where are tests and the bootstrap file:<\/p>\n\n\n\n<pre class=\"wp-block-code is-style-light\"><code>&lt;?xml version=\"1.0\" encoding=\"UTF-8\"?&gt;<br>&lt;phpunit xmlns:xsi=\"http:\/\/www.w3.org\/2001\/XMLSchema-instance\"<br>         xsi:noNamespaceSchemaLocation=\"https:\/\/schema.phpunit.de\/6.3\/phpunit.xsd\"<br>         bootstrap=\"bootstrap.php\"<br>         backupGlobals=\"false\"<br>         colors=\"true\"<br>         beStrictAboutCoversAnnotation=\"false\"<br>         beStrictAboutOutputDuringTests=\"true\"<br>         beStrictAboutTestsThatDoNotTestAnything=\"true\"<br>         beStrictAboutTodoAnnotatedTests=\"true\"<br>         convertErrorsToExceptions=\"true\"<br>         convertNoticesToExceptions=\"true\"<br>         convertWarningsToExceptions=\"true\"<br>         verbose=\"true\"&gt;<br><br>    &lt;testsuites&gt;<br>        &lt;testsuite name=\"unit\"&gt;<br>            &lt;directory suffix=\".php\"&gt;src&lt;\/directory&gt;<br>        &lt;\/testsuite&gt;<br>    &lt;\/testsuites&gt;<br>&lt;\/phpunit&gt;<\/code><\/pre>\n\n\n\n<p id=\"de71\">Once we did that we can add a&nbsp;<strong><em>Test.php<\/em><\/strong>&nbsp;in a&nbsp;<strong><em>src<\/em><\/strong>&nbsp;folder inside&nbsp;<strong><em>Unit<\/em><\/strong>&nbsp;folder with this content to verify everything is well configured:<\/p>\n\n\n\n<pre class=\"wp-block-code is-style-light\"><code>class Test extend TestCase {<br>   public function testShouldReturnTrue() {<br>      $this-&gt;assertTrue(true);<br>   }<br>}<\/code><\/pre>\n\n\n\n<p id=\"95ab\">Then run the following command from the root of your project:<\/p>\n\n\n\n<pre class=\"wp-block-code is-style-light\"><code>.\/vendor\/bin\/phpunit --configuration .\/tests\/Unit\/phpunit.xml.dist<\/code><\/pre>\n\n\n\n<p id=\"9dbf\">It should return you result like this one:<\/p>\n\n\n\n<pre class=\"wp-block-code is-style-light\"><code>PHPUnit 9.5.20 #StandWithUkraineRuntime:       PHP 8.0.18<br>Configuration: .\/tests\/Unit\/phpunit.xml.dist<br>Warning:       Your XML configuration validates against a deprecated schema.<br>Suggestion:    Migrate your XML configuration using \"--migrate-configuration\"!.                                                                   1\/ 1(100%)Time: 00:00.015, Memory: 6.00 MBOK (1 tests, 1 assertions)<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"bbb2\">Mock WordPress functions<\/h2>\n\n\n\n<p id=\"78dd\">Now that we have configure\u00a0<a href=\"https:\/\/phpunit.de\/\" target=\"_blank\" rel=\"noreferrer noopener nofollow\"><strong>PHPUnit<\/strong><\/a>, we will now focus on a problem more linked to WordPress itself.<\/p>\n\n\n\n<p id=\"9a64\">As a WordPress developer you know for sure that plugins and themes are based on global functions.<\/p>\n\n\n\n<p id=\"d337\">Theses functions are a problem when testing as they are not defined when we tests.<\/p>\n\n\n\n<p id=\"a012\">For that a library will help us,\u00a0<a href=\"https:\/\/brain-wp.github.io\/BrainMonkey\/\" target=\"_blank\" rel=\"noreferrer noopener nofollow\"><strong>Brain Monkey<\/strong><\/a>\u00a0that allow to mock global functions easily.<\/p>\n\n\n\n<p id=\"51ff\">To do install this library, run this command:<\/p>\n\n\n\n<pre class=\"wp-block-code is-style-light\"><code>composer require brain\/monkey --dev <\/code><\/pre>\n\n\n\n<p id=\"8a4b\">Once this command is executed , we need to change a bit the\u00a0<strong><em>TestCase.php<\/em><\/strong>\u00a0file as\u00a0<a href=\"https:\/\/brain-wp.github.io\/BrainMonkey\/\" target=\"_blank\" rel=\"noreferrer noopener nofollow\"><strong>Brain Monkey<\/strong><\/a>\u00a0needs to know when the test start or finish:<\/p>\n\n\n\n<pre class=\"wp-block-code is-style-light\"><code>&lt;?php<br><br>use PHPUnit\\Framework\\TestCase as BaseTestCase;<br>use Brain\\Monkey;abstract class TestCase extends BaseTestCase<br>{<br>    protected function setUp() {<br>        parent::setUp();<br>        Monkey\\setUp();<br>    }<br><br>    protected function tearDown() {<br>        Monkey\\tearDown();<br>        parent::tearDown();<br>    }<br>}<\/code><\/pre>\n\n\n\n<p id=\"d07e\">Once the library is configured, lets see how to use it.<\/p>\n\n\n\n<p id=\"a279\"><a href=\"https:\/\/brain-wp.github.io\/BrainMonkey\/\" target=\"_blank\" rel=\"noreferrer noopener nofollow\"><strong>Brain Monkey<\/strong><\/a>\u00a0offer a lot of way to mock different types of functions:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Actions linked functions which are defined when loading\u00a0<a href=\"https:\/\/brain-wp.github.io\/BrainMonkey\/\" target=\"_blank\" rel=\"noreferrer noopener nofollow\"><strong>Brain Monkey<\/strong><\/a>\u00a0and for which an facade is available to mock them.<\/li>\n\n\n\n<li>Filters linked functions which are defined when loading\u00a0<a href=\"https:\/\/brain-wp.github.io\/BrainMonkey\/\" target=\"_blank\" rel=\"noreferrer noopener nofollow\"><strong>Brain Monkey<\/strong><\/a>\u00a0and for which an facade is available to mock them.<\/li>\n\n\n\n<li>Other functions for which an interface is available to mock them.<\/li>\n<\/ul>\n\n\n\n<p id=\"c0e8\">To mock a global function with\u00a0<a href=\"https:\/\/brain-wp.github.io\/BrainMonkey\/\" target=\"_blank\" rel=\"noreferrer noopener nofollow\"><strong>Brain Monkey<\/strong><\/a>\u00a0we first need to import the facade then use the\u00a0<strong><em>expect<\/em><\/strong>\u00a0function:<\/p>\n\n\n\n<pre class=\"wp-block-code is-style-light\"><code>use Brain\\Monkey\\Functions;Functions\\expect('a_global_function');<\/code><\/pre>\n\n\n\n<p id=\"c915\">It is possible to specify parameters with the&nbsp;<strong><em>with<\/em><\/strong>&nbsp;function or a result with&nbsp;<strong><em>andReturn<\/em><\/strong>&nbsp;function:<\/p>\n\n\n\n<pre class=\"wp-block-code is-style-light\"><code>use Brain\\Monkey\\Functions;Functions\\expect('a_global_function')-&gt;with('param1', 'param2')-&gt;andReturn(11);<\/code><\/pre>\n\n\n\n<p id=\"9e0e\">As you might notice\u00a0<a href=\"https:\/\/brain-wp.github.io\/BrainMonkey\/\" target=\"_blank\" rel=\"noreferrer noopener nofollow\"><strong>Brain Monkey<\/strong><\/a>\u00a0use the same functions as\u00a0<a href=\"http:\/\/docs.mockery.io\/en\/latest\/\" target=\"_blank\" rel=\"noreferrer noopener nofollow\"><strong>Mockery<\/strong><\/a>\u00a0as it is based on it.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"22f5\">Use fixtures<\/h2>\n\n\n\n<p id=\"8e7e\">The next point I want to cover with you about testing is fixtures which is a functionality that will allowing you to save ton of time maintaining your unit tests.<\/p>\n\n\n\n<p id=\"e3f8\">Fixtures are a functionality under\u00a0<a href=\"https:\/\/phpunit.de\/\" target=\"_blank\" rel=\"noreferrer noopener nofollow\"><strong>PHPUnit<\/strong><\/a>\u00a0that allow a programmer to pass parameters to a test function changing the behavior of the test without having to copy paste the code. This reducing the amount of code the developer has to write.<\/p>\n\n\n\n<p id=\"bd90\">In this part, we will configure and create an example test using fixtures.<\/p>\n\n\n\n<p id=\"6637\">To configure fixtures the first step is to create a new folder in&nbsp;<strong><em>tests<\/em><\/strong>&nbsp;folder named&nbsp;<strong><em>Fixtures<\/em><\/strong>&nbsp;that will contain our fixtures.<\/p>\n\n\n\n<p id=\"402f\">Then the second step will be to change the&nbsp;<strong><em>TestCase.php<\/em><\/strong>&nbsp;file to add methods to load fixtures for each tests:<\/p>\n\n\n\n<pre class=\"wp-block-code is-style-light\"><code>&lt;?php<br><br>use PHPUnit\\Framework\\TestCase as BaseTestCase;<br>use ReflectionObject;<br><br>abstract class TestCase extends BaseTestCase<br>{<br>    public function configTestData() {<br>        if (empty($this-&gt;config)) {<br>            $this-&gt;loadTestDataConfig();<br>        }<br><br>        return isset( $this-&gt;config&#91;'test_data'] )<br>            ? $this-&gt;config&#91;'test_data']<br>            : $this-&gt;config;<br>    }<br><br>    protected function loadTestDataConfig() {<br>        $obj      = new ReflectionObject($this);<br>        $filename = $obj-&gt;getFileName();<br><br>        $this-&gt;config = $this-&gt;getTestData(dirname($filename), basename($filename, '.php'));<br>    }<br><em><br>    <\/em>protected function getTestData( $dir, $filename ) {<br>        if ( empty( $dir ) || empty( $filename ) ) {<br>            return &#91;];<br>        }<br><br>        $dir = str_replace('Unit', 'Fixtures', $dir);<br>        $dir = rtrim($dir, '\\\\\/');<br>        $testdata = \"$dir\/{$filename}.php\";<br><br>        return is_readable($testdata)<br>            ? require $testdata<br>            : &#91;];<br>    }    protected function setUp() {<br>        parent::setUp();<br>        Monkey\\setUp();<br>    }<br><br>    protected function tearDown() {<br>        Monkey\\tearDown();<br>        parent::tearDown();<br>    }<br>}<\/code><\/pre>\n\n\n\n<p id=\"657f\">With our new TestCase we can now add a provider on our test to load the Fixture:<\/p>\n\n\n\n<pre class=\"wp-block-code is-style-light\"><code>class Test extend TestCase {   \/**<br>   * @dataProvider configTestData<br>   *\/<br>   public function testShouldReturnTrue($config, $expected) {<br>      $this-&gt;assertEquals($config&#91;'value'], $expected);<br>   }<br>}<\/code><\/pre>\n\n\n\n<p id=\"39bb\">Now to create our fixture file we just need to create a file with the same path (<strong><em>Fixtures\/src\/Test.php<\/em><\/strong>) as the test in the&nbsp;<strong><em>Fixtures<\/em><\/strong>&nbsp;folder containing an array with data to pass to the test:<\/p>\n\n\n\n<pre class=\"wp-block-code is-style-light\"><code>&lt;?php<br>return &#91;<br>   'scenario1' =&gt; &#91;<br>        'config' =&gt; &#91;<br>            'value' =&gt; true,<br>        ],<br>        'expected' =&gt; true,<br>   ],<br>   'scenario2' =&gt; &#91;<br>        'config' =&gt; &#91;<br>            'value' =&gt; false,<br>        ],<br>        'expected' =&gt; false,<br>   ],<br>];<\/code><\/pre>\n\n\n\n<p id=\"c20b\">Once this is done our fixtures are configure and we can run the command to launch\u00a0<a href=\"https:\/\/phpunit.de\/\" target=\"_blank\" rel=\"noreferrer noopener nofollow\"><strong>PHPUnit<\/strong><\/a>\u00a0again:<\/p>\n\n\n\n<pre class=\"wp-block-code is-style-light\"><code>.\/vendor\/bin\/phpunit --configuration .\/tests\/Unit\/phpunit.xml.dist<\/code><\/pre>\n\n\n\n<p id=\"dd4a\">It should return you result like this one:<\/p>\n\n\n\n<pre class=\"wp-block-code is-style-light\"><code>PHPUnit 9.5.20 #StandWithUkraineRuntime:       PHP 8.0.18<br>Configuration: .\/tests\/Unit\/phpunit.xml.dist<br>Warning:       Your XML configuration validates against a deprecated schema.<br>Suggestion:    Migrate your XML configuration using \"--migrate-configuration\"!..                                                                  2 \/ 2 (100%)Time: 00:00.015, Memory: 6.00 MBOK (2 tests, 2 assertions)<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"bda3\">Make your classes easier to test<\/h2>\n\n\n\n<p id=\"fcbd\">Now that we configure our tests well we will start to look around it and the first point will be to make your code easier to test.<\/p>\n\n\n\n<p id=\"af29\">Today WordPress developers have some practices that make testing more complex.<\/p>\n\n\n\n<p id=\"a1bb\">The first practice is to write filters and actions in the constructor from the classes. This is problematic because it force the developer to mock actions and filters for tests form all functions from the class.<\/p>\n\n\n\n<p id=\"3e1b\">Instead registering actions and filters in another method that is called after the class is initialized allow to test method from the class easier.<\/p>\n\n\n\n<p id=\"6576\">Another practice is to add global PHP inside the class file forcing the code to be executed when we load the file.<\/p>\n\n\n\n<p id=\"eb4d\">For that the solution I preconise is to follow\u00a0<a href=\"https:\/\/www.php-fig.org\/psr\/psr-4\/\" target=\"_blank\" rel=\"noreferrer noopener nofollow\"><strong>PSR-4<\/strong><\/a>\u00a0conventions as much as you can in your code:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Only one class per file.<\/li>\n\n\n\n<li>Use namespaces.<\/li>\n\n\n\n<li>Split\u00a0<a href=\"https:\/\/www.php-fig.org\/psr\/psr-4\/\" target=\"_blank\" rel=\"noreferrer noopener nofollow\"><strong>PSR-4<\/strong><\/a>\u00a0files from the others.<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"849d\">Calculate coverage<\/h2>\n\n\n\n<p id=\"c7c9\">Once we have tests the next step is to know which code we tested which we did not and for that a tool called code coverage exists.<\/p>\n\n\n\n<p id=\"2d27\">However this tool has some problem.<\/p>\n\n\n\n<p id=\"979e\">When a test is covering a line this tool won\u2019t try to see if there are multiple logical path on this line and will just mark the line as covered even if we did only test it one way.<\/p>\n\n\n\n<p id=\"65d7\">This problem is easy to see with a simple if:<\/p>\n\n\n\n<pre class=\"wp-block-code is-style-light\"><code>if($a == 1 || $b == 2) {<\/code><\/pre>\n\n\n\n<p id=\"ace4\">Imagine we have a test that test with&nbsp;<strong><em>$a = 1&nbsp;<\/em><\/strong>then the second part of the line won\u2019t be tested but the line will be marked as covered.<\/p>\n\n\n\n<p id=\"bf5e\">To prevent this problem I prefer using another tool to do coverage named mutation testing. Even if its name looks like more tests to write you have if fact nothing to do expect running the library and then the library will provide you a coverage from your code.<\/p>\n\n\n\n<p id=\"73ea\">How this tool is different from vanilla code coverage?<\/p>\n\n\n\n<p id=\"f15d\">Here instead of check if a unit test passed by the line, the tool will create mutant based on a variation in the code which can be mutation from the visibility from a function, changing an operator or removing the call to a function.<\/p>\n\n\n\n<p id=\"d6c1\">Then it will check if with your test each mutation is failing and if it is not the case the percentage of mutation that passed your tests giving you a coverage from your code.<\/p>\n\n\n\n<p id=\"b42a\">In PHP, a library that provide us mutation tests is\u00a0<a href=\"https:\/\/infection.github.io\/\" target=\"_blank\" rel=\"noreferrer noopener nofollow\"><strong>Infection<\/strong><\/a>\u00a0and in this part we will see how to install it and use it.<\/p>\n\n\n\n<p id=\"b30e\">To install it, we can use\u00a0<a href=\"https:\/\/getcomposer.org\/\" target=\"_blank\" rel=\"noreferrer noopener nofollow\"><strong>Composer<\/strong><\/a>\u00a0to install it with this command:<\/p>\n\n\n\n<pre class=\"wp-block-code is-style-light\"><code>composer require infection\/infection --dev<\/code><\/pre>\n\n\n\n<p id=\"0222\">Then the next step is to configure it by creating&nbsp;<code>infection.json.dist<\/code>&nbsp;file with this content:<\/p>\n\n\n\n<pre class=\"wp-block-code is-style-light\"><code>{<br>    \"source\": {<br>        \"directories\": &#91;<br>            \"src\"<br>        ]<br>    },<br>    \"phpUnit\": {<br>        \"configDir\": \"tests\\\/Unit\"<br>    },<br>    \"mutators\": {<br>        \"@default\": true<br>    }<br>}<\/code><\/pre>\n\n\n\n<p id=\"9d47\">Then you just have to run the following command and\u00a0<a href=\"https:\/\/infection.github.io\/\" target=\"_blank\" rel=\"noreferrer noopener nofollow\"><strong>Infection<\/strong><\/a>\u00a0will tell you which problems are present in your tests:<\/p>\n\n\n\n<pre class=\"wp-block-code is-style-light\"><code>.\/vendor\/bin\/infection<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"1aa5\">Automate tests run<\/h2>\n\n\n\n<p id=\"bfd1\">Once we finished our unit tests setup, we will automate what can we can.<\/p>\n\n\n\n<p id=\"d178\">For that we will use&nbsp;<a href=\"https:\/\/github.com\/BrainMaestro\/composer-git-hooks\" rel=\"noreferrer noopener\" target=\"_blank\"><strong>Composer Git Hooks<\/strong><\/a>&nbsp;that will allow us to handle Git hooks from&nbsp;<strong><em>composer.json<\/em><\/strong>&nbsp;file.<\/p>\n\n\n\n<p id=\"68b8\">The first will be to simply commands we run with&nbsp;<a href=\"https:\/\/getcomposer.org\/\" rel=\"noreferrer noopener\" target=\"_blank\"><strong>Composer<\/strong><\/a>.<\/p>\n\n\n\n<p id=\"b28a\">For that will have to add the following lines in your&nbsp;<strong><em>composer.json<\/em><\/strong>:<\/p>\n\n\n\n<pre class=\"wp-block-code is-style-light\"><code>\"scripts\": {<br>    \"unit\": \"phpunit --configuration tests\/Unit\/phpunit.xml.dist\",<br>    \"coverage\": \"infection --min-msi=50\"<br>}<\/code><\/pre>\n\n\n\n<p id=\"3647\">Now we can run unit tests with this command:<\/p>\n\n\n\n<pre class=\"wp-block-code is-style-light\"><code>composer run unit<\/code><\/pre>\n\n\n\n<p id=\"c918\">And mutation tests with this command (the command will fail if the coverage is inferior to 50%):<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">composer run coverage<\/pre>\n\n\n\n<p id=\"a5bc\">We will now install\u00a0<a href=\"https:\/\/github.com\/BrainMaestro\/composer-git-hooks\" target=\"_blank\" rel=\"noreferrer noopener nofollow\"><strong>Composer Git Hooks<\/strong><\/a>\u00a0with the following command:<\/p>\n\n\n\n<pre class=\"wp-block-code is-style-light\"><code>composer require --dev brainmaestro\/composer-git-hooks<\/code><\/pre>\n\n\n\n<p id=\"3eed\">And configure it by adding this to&nbsp;<strong><em>composer.json<\/em><\/strong>:<\/p>\n\n\n\n<pre class=\"wp-block-code is-style-light\"><code>\"scripts\": {<br>    \"unit\": \"phpunit --configuration tests\/Unit\/phpunit.xml.dist\",<br>    \"coverage\": \"infection --min-msi=50\",<br>    \"cghooks\": \"cghooks\",<br>    \"post-install-cmd\": \"cghooks add --ignore-lock\",<br>    \"post-update-cmd\": \"cghooks update\"<br>},<br>\"extra\": {<br>    \"hooks\": {<br>        \"config\": {<br>            \"stop-on-failure\": &#91;\"pre-push\"]<br>        },<br>        \"pre-push\": &#91;<br>            \"unit\",<br>            \"coverage\"<br>        ]<br>    }<br>}<\/code><\/pre>\n\n\n\n<p id=\"499e\">We will now have to run manually the following command to install hooks:<\/p>\n\n\n\n<pre class=\"wp-block-code is-style-light\"><code>composer run post-install-cmd<\/code><\/pre>\n\n\n\n<p id=\"ed00\">However with&nbsp;<strong><em>post-install-cmd<\/em><\/strong>&nbsp;and&nbsp;<strong><em>post-update-cmd&nbsp;<\/em>hooks will be installed by themself on any composer install or update.<\/strong><\/p>\n\n\n\n<p id=\"821b\">Now every time we push some code both unit test and coverage is runned automatically.<\/p>\n\n\n\n<p id=\"2857\">If we want to skip theses hooks we can use&nbsp;<strong><em>-n<\/em><\/strong>&nbsp;on your git command.<\/p>\n\n\n\n<p id=\"fc8a\">That\u2019s it that all for this first article on testing on WordPress, I hope you enjoy it and if you are interested I will publish new ones on Integration testing and Acceptance testing on WordPress.<\/p>","protected":false},"excerpt":{"rendered":"<p>Automated tests are the base of modern programming development process and are as important as the architecture from the code itself.<\/p>\n<p>As they are what prevent regression in your project preventing your project to crumble on itself.<\/p>\n<p>In this article, we will focus more particularly on unit test.<\/p>","protected":false},"author":1,"featured_media":162,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":false,"jetpack_social_options":{"image_generator_settings":{"template":"highway","enabled":false},"version":2}},"categories":[26,18],"tags":[19,20,32,33,5],"class_list":["post-161","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-testing","category-wordpress","tag-php","tag-plugin-development","tag-test-automation","tag-unit-testing","tag-wordpress"],"jetpack_publicize_connections":[],"acf":[],"_links":{"self":[{"href":"https:\/\/www.mitango.app\/fr\/wp-json\/wp\/v2\/posts\/161","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.mitango.app\/fr\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.mitango.app\/fr\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.mitango.app\/fr\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.mitango.app\/fr\/wp-json\/wp\/v2\/comments?post=161"}],"version-history":[{"count":1,"href":"https:\/\/www.mitango.app\/fr\/wp-json\/wp\/v2\/posts\/161\/revisions"}],"predecessor-version":[{"id":163,"href":"https:\/\/www.mitango.app\/fr\/wp-json\/wp\/v2\/posts\/161\/revisions\/163"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.mitango.app\/fr\/wp-json\/wp\/v2\/media\/162"}],"wp:attachment":[{"href":"https:\/\/www.mitango.app\/fr\/wp-json\/wp\/v2\/media?parent=161"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.mitango.app\/fr\/wp-json\/wp\/v2\/categories?post=161"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.mitango.app\/fr\/wp-json\/wp\/v2\/tags?post=161"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}