Unit Testing
Unit Testing is a method for software testing in the scope of which individual units (function, method in a class), their associated data, usage, and operations are tested to determine if these are working as designed.
As this is based on individual unit testing, there is no coupling among units, and that is very easy to test because it avoids complications.
Benefits Of Unit Testing:
Easy to Debug:
Unit testing finds problems early because it isolates each part of the program and shows that individual parts are correct. This includes debugging the program logic and flaws or missing parts of the specification for the unit.
Quality of Code:
As unit testing identifies the bugs at the program level, it improves code quality. It restricts programmers from following the standard to fix the bugs.
Make Program Easy to Change/Upgrade:
Unit testing makes it easy for the programmer to refactor/upgrade the code later. In addition, it creates a high cohesion among programs and makes sure the module works correctly even after changes or upgradation.
Design Accuracy:
Unit testing restricts programmers from following the code standards to focus on specifications for the unit. To fulfill the specifications of a unit, unit testing forces the programmer to think about design too, which makes the design more accurate.
Reduce Costs:
Unit testing helps to find and fix the bugs at an early stage, reducing the cost and saving time to debug the modules later. In addition, it reduces the complexity during System Testing and makes everything smooth in development.
Implementing Unit Testing In Magento 2
Magento 2 has been launched with PHPUnit pre-installed, an automated testing framework for PHP. It has been included as a dependency in Magento 2. So, here is the custom module that will help you understand the basic implementation of Unit Testing. You will see the custom module to check a given string should be alphabetical.
Following are the steps:
Create And Register A New Custom Module
To create a custom module, the first step is to create a file, module.xml in folder, <Magento Root Folder>/app/code/<Vendor Name>/<Module Name>/etc/ folder. Let’s take the path –
/app/code/Bizspice/UnitTesting/etc/module.xml
and paste the following code into this file:
<?xml version="1.0" ?> <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd"> <module name="Bizspice_UnitTesting" setup_version="1.0"> </module> </config>
Now, create a file registration.php in /app/code/Bizspice/UnitTesting/ folder with the following code:
<?php \Magento\Framework\Component\ComponentRegistrar::register( \Magento\Framework\Component\ComponentRegistrar::MODULE, 'Bizspice_UnitTesting', __DIR__ );
Create Model File
Create Alphabet.php under /app/code/Bizspice/UnitTesting/Model folder with the following code:
<?php namespace Bizspice\UnitTesting\Model; class Alphabet { /** * this function will accept and return the string * * @param string str * @return string */ public function getText($str) { if(preg_match("/^[a-zA-Z][a-zA-Z ]*$/", $str)){ return $str; }else{ return false; } }
Here, you can see the getText() function, which checks the string and whether it contains only alphabets or not.
Create Test File:
Now, create a file to test getText() function. Create AlphabetTest.php under /app/code/Bizspice/UnitTesting/Test/Unit/Model/ folder with the following code:
<?php namespace Bizspice\UnitTesting\Test\Unit\Model; class AlphabetTest extends \PHPUnit\Framework\TestCase { protected $_objectManager; protected $_desiredResult; protected $_actualResult; protected $_alphabet; protected $_text; /** * used to set the values to variables or objects. * * @return void */ public function setUp() { $this->_objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); $this->_alphabet = $this->_objectManager->getObject("Bizspice\UnitTesting\Model\Alphabet"); } /** * this function will check if string is having alphabets only */ public function testGetText() { $this->_actualResult = $this->_alphabet->getText("This is my testing string"); $this->_desiredResult = "This is my testing string"; $this->assertEquals($this->_desiredResult, $this->_actualResult); } }
All test files must be named with Test.php as a suffix because it has to be mentioned in the phpunit.xml file. You will see it below soon.
Also, the path of the test files must be the mirror of the files to be tested. For instance, we have created /app/code/Bizspice/UnitTesting/Model/Alphabet.php, so the test file must be located at /app/code/Bizspice/UnitTesting/Test/Unit/Model/AlphabetTest.php.
Enable Module
To test a function/method, its corresponding module must be enabled. So, open the terminal, go to your Magento directory and run the following commands to enable the module:
rm -rf pub/static/* var/* generated/*; chmod 0777 var/ pub/ generated/; chmod 0777 -R var/ generated/ pub/; php bin/magento setup:upgrade php bin/magento setup:di:compile php bin/magento setup:static-content:deploy -fphp bin/magento indexer:reindex php bin/magento cache:clean php bin/magento cache:flush
phpunit.xml
After enabling the module, now it has to be tested. Actually, Magento 2 has made testing very easy, and the <root folder>/dev/tests/unit/phpunit.xml.dist file has to be managed for this.
Rename this file to phpunit.xml and open this file. Go to <testsuite name=”Magento Unit Tests”> tag:Add the following line to the testsuite tag:
<directory suffix=”Test.php”>../../../app/code/Bizspice/UnitTesting/Test/Unit</directory>
As attribute suffix denotes fetch all files having suffix Test.php and existing under /app/code/Bizspice/UnitTesting/Test/Unit directory and operate them.
To make testing faster, let’s comment on other lines under the testsuite tag as per follows:
That’s it! Now you are ready to start Unit Testing.
Unit Testing
To run the test, open terminal and go to your Magento directory and run the following commands:
- cd dev/tests/unit
- php ../../../vendor/phpunit/phpunit/phpunit
It will give you the following output:
Here, you will see that the test has been done successfully as a string with only alphabets passed in the testGetText() function in /app/code/Bizspice/UnitTesting/Test/Unit/Model/AlphabetTest.php –
public function testGetText() { $this->_actualResult = $this->_alphabet->getText("This is my testing string"); $this->_desiredResult = "This is my testing string"; $this->assertEquals($this->_desiredResult, $this->_actualResult); }
Now, to get the failure result, let’s change the string passed in the above function and replace the function with the following code:
public function testGetText() { $this->_actualResult = $this->_alphabet->getText("This is my testing string2222"); $this->_desiredResult = "This is my testing string"; $this->assertEquals($this->_desiredResult, $this->_actualResult); }
Run the following command in the terminal again:
php ../../../vendor/phpunit/phpunit/phpunit
And you will see the following result:
Assertions For Testing
So, you have seen the basic implementation of Unit Testing. There a function assertEquals has been used in the testGetText() function in /app/code/Bizspice/UnitTesting/Test/Unit/Model/AlphabetTest.php. This is an assertion to compare the result for testing.
Following are a few types of Assertions:
assertTrue($x) Fail if $x is false assertFalse($x) Fail if $x is true assertNull($x) Fail if $x is set assertNotNull($x) Fail if $x not set assertIsA($x, $t) Fail if $x is not the class or type $t assertNotA($x, $t) Fail if $x is of the class or type $t assertEqual($x, $y) Fail if $x == $y is false assertNotEqual($x, $y) Fail if $x == $y is true assertWithinMargin($x, $y, $m) Fail if abs($x - $y) < $m is false assertOutsideMargin($x, $y, $m) Fail if abs($x - $y) < $m is true assertIdentical($x, $y) Fail if $x == $y is false or a type mismatch assertNotIdentical($x, $y) Fail if $x == $y is true and types match assertReference($x, $y) Fail unless $x and $y are the same variable assertClone($x, $y) Fail unless $x and $y are identical copies assertPattern($p, $x) Fail unless the regex $p matches $x assertNoPattern($p, $x) Fail if the regex $p matches $x expectError($x) Fail if matching error does not occour expectException($x) Fail if matching exception is not thrown ignoreException($x) Swallows any upcoming matching exception assert($e) Fail on failed expectation object
If you are curious to know more about Unit Testing, check this link (https://phpunit.de/)