Magento 2 - How to Create Unit Testing?

I wrote these tutorials for myself in future when I forget for the next steps.
Search for a command to run...

I wrote these tutorials for myself in future when I forget for the next steps.
No comments yet. Be the first to comment.
Unit Test is the smallest part of testing in Magento 2. Module must has classes and each class must has method(s) on it, that method contains lot of logic, each method return can be null, string, integer, false, etc. So this is where unit test works,...
When you provision an Ubuntu instance on Oracle Cloud, you'll notice something different from standard Ubuntu installations: the system uses iptables instead of ufw for firewall management. This disti

When developing web applications locally, HTTPS is often overlooked. Yet, modern browsers and APIs increasingly require secure connections—even in development. That’s where mkcert comes in: a simple t

Testing the checkout success page in Magento 2 can be frustrating. By default, once an order is placed, Magento clears the quote session, meaning you can’t simply refresh or revisit the success page without going through the entire checkout process a...

Magento Commerce (EE) offers powerful features, but for many teams, Open Source (CE) is leaner, lighter, and more sustainable. If you're migrating from EE to CE, the Opengento downgrade tool provides a clean, scriptable way to remove proprietary modu...

If you’ve ever checked your Apache error logs and seen something like this: Code [core:error] (13)Permission denied: access to /robots.txt denied (filesystem path '/home/username/sites') because search permissions are missing on a component of the pa...

Previously I created an article about what is unit testing, now let's create one Helper class of a Magento 2 Module Fiko\Testing\Helper\Data and then we're going to create unit testing of that class.
You can follow to create this Helper app/code/Fiko/Testing/Helper/Data.php.
<?php
namespace Fiko\Testing\Helper;
use Magento\Store\Model\StoreManagerInterface;
class Data
{
const BORIZQY = 'Borizqy';
/**
* Constructor
*
* @param StoreManagerInterface $storeManager
*/
public function __construct(StoreManagerInterface $storeManager)
{
$this->storeManager = $storeManager;
}
/**
* This method will return what's the bypassed parameter
*
* @param string $name
* @return string
*/
public function getName($name): string
{
return $name;
}
/**
* Getting current store Id
*
* @return void
*/
public function getStoreId()
{
return $this->storeManager->getStore()->getId();
}
/**
* Checking is string parameter borizqy or not?
*
* @param string $surname
* @return boolean
*/
public function isBorizqy($surname)
{
return ucwords(strtolower($surname)) === self::BORIZQY;
}
}
Let's breakdown the helper code.
__construct(StoreManagerInterface $storeManager), I'm going to create constructor method so we have an instance on how to declare constructor of a module in the Unit Testing.
getName($name), This example method should always return the given parameter.
getStoreId(), This method should return current store view id.
isBorizqy($surname), This method should validate the $surname variable passed by the argument.
Once the helper class created, we need to create the Tester Class. Best practice of it are:
to create append Test on each Class (for this instance, it should be DataTest)
to locate the file exactly the same as the declared class under Test\Unit directory of the module. We created Fiko\Testing\Helper\Data, then we need to create Fiko\Testing\Test\Unit\Helper\Data.
We're going to create 4 testing methods, in order to create unit testing we have to:
Create class and extends PHPUnit\Framework\TestCase
prefix the method with test, let's say we want to create testing for isBorizqy, we can have testIsBorizqy method.
<?php
namespace Fiko\Testing\Test\Unit\Helper;
use Fiko\Testing\Helper\Data;
use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
use Magento\Store\Api\Data\StoreInterface;
use Magento\Store\Model\StoreManagerInterface;
use PHPUnit\Framework\TestCase;
class DataTest extends TestCase
{
/**
* This method will be called on every test method
*
* @return void
*/
protected function setUp(): void
{
$this->objectManager = new ObjectManager($this);
$this->storeManager = $this->createMock(StoreManagerInterface::class);
// or we can use this way:
// $this->storeManager = $this->getMockBuilder(StoreManagerInterface::class)
// ->disableOriginalConstructor()
// ->onlyMethods(['getStore']) // it's optional if we want to mock getStore as well
// ->getMockForAbstractClass();
$this->helper = $this->objectManager->getObject(
Data::class,
[
'storeManager' => $this->storeManager
]
);
}
/**
* Testing to get integer for getStoreId
*
* @return void
*/
public function testGetStoreId(): void
{
$storeMock = $this->createMock(StoreInterface::class);
$storeMock->expects($this->once())->method('getId')->willReturn(1);
// or we can use this way:
// $storeMock = $this->getMockBuilder(StoreInterface::class)
// ->disableOriginalConstructor()
// ->onlyMethods(['getId'])
// ->getMockForAbstractClass();
// $storeMock->expects($this->once())->method('getId')->willReturn(1);
$this->storeManager->expects($this->once())->method('getStore')->willReturn($storeMock);
$this->assertIsInt($this->helper->getStoreId());
}
/**
* Test correct name
*
* @param string $name
* @param string $expected
*
* @return void
* @dataProvider getNameDataProvider
*/
public function testGetName($name, $expected): void
{
$this->assertSame($expected, $this->helper->getName($name));
}
/**
* @return array
* @see self::testGetName()
*/
public function getNameDataProvider(): array
{
return [
[
'Fiko',
'Fiko'
],
[
'Borizqy',
'Borizqy'
],
];
}
/**
* Test wrong name
*
* @param string $name
* @param string $expected
* @return void
* @dataProvider wrongNameDataProvider
*/
public function testWrongName($name, $expected): void
{
$this->assertNotSame($expected, $this->helper->getName($name));
}
/**
* @return array
* @see self::testWrongName()
*/
public function wrongNameDataProvider(): array
{
return [
[
'Fiko Input',
'Fiko Expected'
],
[
'Borizqy Input',
'Borizqy Expected'
],
];
}
/**
* Testing is borizqy
*
* @param string $surname
* @param boolean $expected
*
* @return void
* @dataProvider isBorizqyDataProvider
*/
public function testIsBorizqy($surname, $expected)
{
$this->assertSame($expected, $this->helper->isBorizqy($surname));
}
/**
* @return array
* @see self::testIsBorizqy()
*/
public function isBorizqyDataProvider()
{
return [
['Borizqy', true],
['borizqy', true],
['bORIZQY', true],
['BORIZQY', true],
['boRIZQY', true],
['Fiko', false],
];
}
}
Let's breakdown the testing class:
protected function setUp(): void, it's sort of constructor for the unit testing. This method will be called for every testing method execution. We have created 4 testing methods, means that setUp method will be called 4 times before test method.
$this->objectManager->getObject(..., []), this is how we call Helper Class.
first argument will be the class we want to call, in this case it is \Fiko\Testing\Helper\Data:class.
second argument will be the array of the required constructor of the Helper.
$this->storeManager = $this->createMock(StoreManagerInterface::class);, this is how we mocking the constructor requirement. for more information about this, please to this reference.
$this->assertSame / $this->assertNotSame / $this->assertIsInt, they are logic of phpunit to validate our testing. for more information about this, please to read this reference.
to run unit test we can use this to execute all unit tests.
vendor/bin/phpunit -c dev/tests/unit/phpunit.xml.dist
But if we want to specify which unit testing we want to test / execute, we can specify it on the command (e.g. we want to test our created helper testing):
vendor/bin/phpunit -c dev/tests/unit/phpunit.xml.dist app/code/Fiko/Testing/Test/Unit/Helper/DataTest.php
or if we want to test all unit testing inside Fiko_Testing module, we can run
vendor/bin/phpunit -c dev/tests/unit/phpunit.xml.dist app/code/Fiko/Testing/Test/Unit/
References: