Demac Media Demac Media Brand Demac Media Brand

Blog

Subscribe

#RealMagento: Automated Testing in Magento 2

Timer Icon 7 Mins

Development, Magento Commerce

With this post, I aim to show you the basics of how to perform integration and unit testing in Magento 2 through a simple plugin module. This will automate more of your worfklow and grow your confidence in the code you write.

For these tests, we’ll be using the module that we built in this blog post.

A quick note: This article was written shortly after the release of Magento version 2.1.0. Take this into consideration if you notice some differences in file names or the file contents in the Magento version that you’re currently using.

I’m also leaving out the configuration of IDEs, such as PHPStorm, to run unit tests. I will assume that you’ve already set this up or are running the tests from the command line using the phpunit executable, located at /vendor/bin/phpunit, that composer pulls in via the “phpunit/phpunit”: “4.1.0” requirement in the root composer.json file.

Automated Testing in Magento 2

ecommerce, website design, demac media, magento 2, automated testing, magento ecommerce,magento 2 testing

What I will cover:

What I can’t cover:

I would also like to quickly mention Vinai Kopp’s Mage2Kata videos. These are a fantastic resource for Magento 2 testing and test-driven development(or TDD for short). These videos, and Vinai himself, have helped me to learn a lot of the intricacies of writing tests within the large, connected Magento 2 framework

Let’s get started!

The first thing we should do is ensure that our testing-related configuration files are properly set up.

To start writing our integration tests, we need to rename and update the contents of two files that the core provides for us as templates.

After those files have been updated, we can write the first test for our module. The first test will be an integration test to ensure that our module is configured properly and Magento can pick it up.

The first test class file will be located at: /app/code/Demac/WelcomePlugin/Test/Integration/ModuleConfigTest.php and its contents are:

<?php

namespace Demac\WelcomePlugin\Test\Integration;


use Magento\Framework\Component\ComponentRegistrar;
use Magento\Framework\Module\ModuleList;
use Magento\TestFramework\ObjectManager;

class ModuleConfigTest extends \PHPUnit_Framework_TestCase
{
   private $subjectModuleName;

   /**
    * @var $objectManager ObjectManager
    */
   private $objectManager;

   protected function setUp()
   {
       $this->subjectModuleName = 'Demac_WelcomePlugin';
       /** @var ObjectManager objectManager */
       $this->objectManager = ObjectManager::getInstance();
   }

   public function testTheModuleIsRegistered()
   {
       $registrar = new ComponentRegistrar();
       $this->assertArrayHasKey('Demac_WelcomePlugin', $registrar->getPaths(ComponentRegistrar::MODULE));
   }

   public function testTheModuleIsConfiguredInTheTestEnvironment()
   {
       /** @var $moduleList ModuleList */
       $moduleList = $this->objectManager->create(ModuleList::class);
       $this->assertTrue($moduleList->has($this->subjectModuleName));
   }

   public function testTheModuleIsConfiguredInTheRealEnvironment()
   {
       /** @var $objectManager ObjectManager */
       $this->objectManager = ObjectManager::getInstance();

       // The tests by default point to the wrong config directory for this test.
       $directoryList = $this->objectManager->create(
           \Magento\Framework\App\Filesystem\DirectoryList::class,
           ['root' => BP]
       );
       $deploymentConfigReader = $this->objectManager->create(
           \Magento\Framework\App\DeploymentConfig\Reader::class,
           ['dirList' => $directoryList]
       );
       $deploymentConfig = $this->objectManager->create(
           \Magento\Framework\App\DeploymentConfig::class,
           ['reader' => $deploymentConfigReader]
       );

       /** @var $moduleList ModuleList */
       $moduleList = $this->objectManager->create(
           ModuleList::class,
           ['config' => $deploymentConfig]
       );
       $this->assertTrue($moduleList->has($this->subjectModuleName));
   }
}

If you followed our previous post, these tests should pass as you’ll have already created the registration.php and etc/module.xml files for this module as well as enabled your module via $ bin/magento module:enable Demac_WelcomePlugin

Next, we’ll write some tests to ensure that our plugin is registered within the proper application area and that it returns the expected values.

The test class file will be located at: /app/code/Demac/WelcomePlugin/Test/Integration/Plugin/WelcomePluginTest.php and its contents are:

<?php

namespace Demac\WelcomePlugin\Test\Integration\Plugin;


use Demac\WelcomePlugin\Plugin\WelcomePlugin;
use Magento\Framework\App\Area;
use Magento\TestFramework\App\State;
use Magento\TestFramework\Interception\PluginList;
use Magento\TestFramework\ObjectManager;

class WelcomePluginTest extends \PHPUnit_Framework_TestCase
{
   /**
    * @var ObjectManager
    */
   private $objectManager;

   private function setAppState($appState)
   {
       /** @var State $appState */
       $appState = $this->objectManager->create(State::class);
       $appState->setAreaCode($appState);
   }

   protected function setUp()
   {
       $this->objectManager = ObjectManager::getInstance();
   }

   protected function tearDown()
   {
       $this->setAppState(null);
   }

   public function testThePluginIsRegistered()
   {
       $this->setAppState(Area::AREA_FRONTEND);

       /** @var PluginList $pluginList */
       $pluginList = $this->objectManager->create(PluginList::class);
       $pluginInfo = $pluginList->get(WelcomePlugin::class, []);

       $this->assertSame(WelcomePlugin::class, $pluginInfo['demac_welcomeplugin']['instance']);
   }
}

Now let’s add our third test case: our unit tests.

/app/code/Demac/WelcomePlugin/Test/Unit/Plugin/WelcomePluginTest.php and its contents are:

<?php

namespace Demac\WelcomePlugin\Test\Unit\Plugin;


use Demac\WelcomePlugin\Plugin\WelcomePlugin;
use Magento\Framework\Message\ManagerInterface as MessageManager;


class WelcomePluginTest extends \PHPUnit_Framework_TestCase
{
  /**
   * @var WelcomePlugin
   */
  private $plugin;


  /**
   * @var MessageManager
   */
  private $messageManager;


  protected function setUp()
  {
      $this->messageManager = $this->getMockForAbstractClass(MessageManager::class, ['addSuccessMessage']);
      $this->plugin = new WelcomePlugin($this->messageManager);
  }


  public function testAfterSetCustomerDataAsLoggedInMethodCanBeCalled()
  {
      $session = $this->getMockBuilder(\Magento\Customer\Model\Session::class)
          ->disableOriginalConstructor()
          ->getMock();


      $this->messageManager->expects($this->once())
          ->method('addSuccessMessage')
          ->willReturn($this->messageManager);


      $this->assertSame(
          $session,
          $this->plugin->afterSetCustomerDataAsLoggedIn($session, $session)
      );
  }
}
  • I should point out that all of the dependencies, besides the subject under test (our Plugin class), are mocked out to ensure that the only thing affecting the outcome is the code being tested.
  • All of the mocking that I did in the above code was supported by the mocking features of PHPUnit and was not at all dependent on Magento 2.

Now just run your unit and integration tests. All you should see is green!

Now it’s your turn!

ecommerce, website design, demac media, magento 2, automated testing, magento ecommerce,magento 2 testing

Writing well-tested, maintainable modules in Magento 2 is just like any other skill; practice makes perfect. Start by simply testing your modules first. Then experiment with test-driven development to see where it does and doesn’t work for you.

Stay tuned for more Magento 2 content soon!

ecommerce, website design, demac media, magento 2, automated testing, magento ecommerce,magento 2 testing

Subscribe to the Blog

Stay updated with 20,000+ eCommerce leaders in our community

Sign Up

Let’s talk about your 10X return

Icon/Social/Phone Contact us for pricing information