How to Do Magento Unit Testing with PHP Unit

Unit testing helps developers write better and cleaner code, avoiding logical errors. When developing a large project, there are critical things that you need to keep in mind, such as the plan for project, its design, etc. All of those things are dependent on the way the code is written. Code should be well written […]

By Ledian Hymetllari

magento php unit
Unit testing helps developers write better and cleaner code, avoiding logical errors. When developing a large project, there are critical things that you need to keep in mind, such as the plan for project, its design, etc. All of those things are dependent on the way the code is written. Code should be well written and have a low execution time.

For example, say that we are writing code to fix a bug. After correcting the code, the developer will open a browser to test his or her changes against the bug. However, the code that was modified may affect other areas of the application outside the function that is currently being tested. For that reason, the best method is for the developer to test not just the problem he or she is trying to solve, but to perform a full test of the whole system.

This might sound like it would take a long time, but really it doesn’t have to. That’s where unit testing comes in. Unit testing allows the developer to test against different types of data instead of manually testing in the browser. It is better and faster to do code tests this way because you can quickly test with different scenarios.

PHPUnit, developed by Sebastian Bergmann, is a programmer-oriented testing framework for PHP and is a popular tool for unit testing in Magento. It is an instance of the xUnit architecture for unit testing frameworks.

In this article, we will look at a simple example of how PHPUnit can be used for unit testing in Magento. Before following the example, you will want to visit www.phpunit.de, where you can learn how to install it. You will also find official documentation there to take you beyond the scope of this introduction.

Here are a few tips regarding PHPUnit you should keep in mind before we start:

  • For each class you intend to test, you should have a test class for that purpose.
  • Every test class should extend the PHPUnit_Framework_TestCase class.
  • Test classes should have the name of the class you are testing, followed by “Test.” For example, if the Class name is Customer.php, The test class name should be CustomerTest.php.
  • Every method you are writing for testing with a test class should begin with “test” For example: testGetCustomerName().
  • Test methods never get parameters.
  • All test methods need to be public to be executed from PHPUnit. You can have private methods in case you need them as helper methods, but they won’t be executed from PHPUnit.

You will want to understand these two methods:
setUp() Sets up the fixture, for example, open a network connection. This method is called before a test is executed.

tearDown() Tears down the fixture, for example, closing a network connection. This method is called after a test is executed.

Now we’ll take a look at a simple example to explain what Unit Testing can do:

Let’s write a simple class here to check if a specific URL results in a 404 Error.


/**
* Copyright (c) 2017 Sherodesigns.
* *
* @Project html
* @date 2/14/2017
* @author Sherodesigns | Ledian
* @link https://sherocommerce.com/
* @description UNIT TESTING
*/

class UrlExists
    {
        /*
        Check if url is not 404
        */
        public function isUrl404NotFound($url = null)
          {
              if($url == null) {
                  throw new Exception("That's not a url name!");
              }
                  $file_headers = @get_headers($url);
                  if(!$file_headers || $file_headers[0] == 'HTTP/1.1 404 Not Found') {
                  return true;
              }
              else {
                  return false;
              }
          }

     }

To test this class I am creating a test class extending from PHPUnit_Framework_TestCase:


/**
* Copyright (c) 2017 Sherodesigns.
* *
* @Project html
* @date 2/14/2017
* @author Sherodesigns | Ledian
* @link https://sherocommerce.com/
* @description Unit testing
*/

equire_once('UrlExists.php');
class UrlExistsTest extends PHPUnit_Framework_TestCase {
    public function setUp() { }
    public function tearDown() { }
    public function testCheckUrl() { 
        $object = new UrlExists(); $this->assertTrue($object->isUrl404NotFound('https://sherocommerce.com/') === true);
    }
}

Let’s open terminal and execute our test class using PHPUnit:

phpunit UrlExistsTest.php

After executing above class I am getting this result:


PHPUnit 5.7.5 by Sebastian Bergmann and contributors.

F 1 / 1 (100%)

Time: 1.29 seconds, Memory: 13.75MB

There was 1 failure:

1) UrlExistsTest::testCheckUrl
Failed asserting that false is true.

/home/vagrant/html/PHPUnitExample/UrlExistsTest.php:23

FAILURES!
Tests: 1, Assertions: 1, Failures: 1.
vagrant@magento-one:~/html/PHPUnitExample$

This meant that my url https://sherocommerce.com/ is not 404.
In case I set url like below in the assertTrue method
$this->assertTrue($object->isUrl404NotFound('https://sherocommerce.com/test404') === true);

Php unit will show the following result:

PHPUnit 5.7.5 by Sebastian Bergmann and contributors.

. 1 / 1 (100%)

Time: 1.43 seconds, Memory: 13.75MB

OK (1 test, 1 assertion)
vagrant@magento-one:~/html/PHPUnitExample$

This means that PHPUnit executed successfully.

You can fork the above example from this Git repository.

Below is a list of common methods that you can try using in your tests:

AssertTrue($condition, $message='')
Asserts/Check that a condition is true.

AssertFalse($condition, $message='')
Asserts/Check that a condition is false.

AssertEquals($expected, $actual, $message = '', $delta = 0.0, $maxDepth = 10, $canonicalize = false, $ignoreCase = false)
Asserts that two variables are equal.

AssertGreaterThan($expected, $actual, $message = '')
Asserts that a value is greater than another value.

AssertContains($needle, $haystack, $message = '', $ignoreCase = false, $checkForObjectIdentity = true, $checkForNonObjectIdentity = false)
Asserts that a haystack contains a needle.

assertSame($expected, $actual, $message = '')
Asserts that two variables have the same type and value. Used on objects, it asserts that two variables reference the same object.

AssertNull($actual, $message = '')
Asserts that a variable is null.

AssertFileExists($filename, $message = '')
Asserts/Checks that a file exists.

AssertRegExp
Check the input against a regular expression.

Effective unit testing takes practice. Try experimenting with different unit testing methods to better understand the logic used to test your code.

The above example demonstrates a simple PHP unit test. The next challenge of unit testing will be to unit test in Magento.

A simple structure example of unit testing for Magento can be forked from this Git repository.

The following image demonstrates the structure of unit testing files. This module can be placed in the webroot of your Magento files. You can use it with Modman too. Generate symlinks for your projects, run your test code, then you can remove symlinks and this module won’t be used from Magento.

Let’s see how this module will work:
Assume that you have a module on local code pool named Shero_Example, and you would like to test a block class called Example.php

To test this block class you should create the same module structure there and the test class, ExampleTest.php in this case. If it looks abstract, don’t worry; I’ll explain it with an example.

The structure will be: Shero/Example/Block/ExampleTest.php. It will look like this:

ExampleTest.php will contain test methods to test Example.php class from your module.

Let’s take a real world example. We’ll test a model method from in this path:

app/code/local/Shero/Events/Model/Attribute/Datetime.php.

This is a class of autoreminder extension that you can find on this Git repository. This class contains the method formatDate($date)

You can fork this here here.

Add a test folder in your root web directory. After that, cd into sherounit/unit/test.

Then run phpunit.phar and you will see the result like this :



OK (2 tests, 1 assertion)
vagrant@magento-one:~/magento1/html/sheromagentodevelopment/public_html/sherounit/unit$ ~/phpunit.phar
PHPUnit 5.7.5 by Sebastian Bergmann and contributors.

.F 2 / 2 (100%)

Time: 982 ms, Memory: 24.75MB

There was 1 failure:

1) Shero_Events_Model_Attribute_DatetimeTest::testFormatDate
Failed asserting that two strings are equal.
--- Expected
+++ Actual
@@ @@
-'2017-05-02'
+'2015-03-03 00:00:00'

/home/vagrant/magento1/html/sheromagentodevelopment/public_html/sherounit/unit/test/Shero/Events/Model/Attribute/DatetimeTest.php:28

FAILURES!
Tests: 2, Assertions: 1, Failures: 1.
vagrant@magento-one:~/magento1/html/sheromagentodevelopment/public_html/test/unit$

Want to know more? Here are some helpful resources:

www.atwix.com/magento/php-unit-testing/
www.sitepoint.com/

Questions? Write a comment below!

Back End Developer