# Magento 2 - How to Create Unit Testing?

Previously I created an article about [what is unit testing](https://s.id/1x0uS), 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.

### 1\. Create Helper

You can follow to create this Helper `app/code/Fiko/Testing/Helper/Data.php`.

```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.

1. <mark>__construct(StoreManagerInterface $storeManager)</mark>, I'm going to create constructor method so we have an instance on how to declare constructor of a module in the Unit Testing.
    
2. <mark>getName($name)</mark>, This example method should always return the given parameter.
    
3. <mark>getStoreId()</mark>, This method should return current store view id.
    
4. <mark>isBorizqy($surname)</mark>, This method should validate the `$surname` variable passed by the argument.
    

### 2\. Creating Unit Test

Once the helper class created, we need to create the Tester Class. Best practice of it are:

1. to create append `Test` on each Class (for this instance, it should be `DataTest`)
    
2. to locate the file exactly the same as the declared class under <mark>Test\Unit</mark> directory of the module. We created <mark>Fiko\Testing\Helper\Data</mark>, then we need to create <mark>Fiko\Testing\Test\Unit\Helper\Data</mark>.
    

We're going to create 4 testing methods, in order to create unit testing we have to:

1. Create class and extends `PHPUnit\Framework\TestCase`
    
2. prefix the method with `test`, let's say we want to create testing for `isBorizqy`, we can have `testIsBorizqy` method.
    

```php
<?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:

1. <mark>protected function setUp(): void</mark>, 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.
    
2. <mark>$this-&gt;objectManager-&gt;getObject(..., [])</mark>, this is how we call Helper Class.
    
    1. first argument will be the class we want to call, in this case it is `\Fiko\Testing\Helper\Data:class`.
        
    2. second argument will be the array of the required constructor of the Helper.
        
3. <mark>$this-&gt;storeManager = $this-&gt;createMock(StoreManagerInterface::class);</mark>, this is how we mocking the constructor requirement. for more information about this, please to [this reference](https://s.id/1x0JD).
    
4. <mark>$this-&gt;assertSame</mark> / <mark>$this-&gt;assertNotSame</mark> / <mark>$this-&gt;assertIsInt</mark>, they are logic of phpunit to validate our testing. for more information about this, please to read [this reference](https://s.id/1x0Kg).
    

### 3\. Run Unit Test

to run unit test we can use this to execute all unit tests.

```bash
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):

```bash
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

```bash
vendor/bin/phpunit -c dev/tests/unit/phpunit.xml.dist app/code/Fiko/Testing/Test/Unit/
```

---

References:

* [https://developer.adobe.com/commerce/testing/guide/unit/command-line/](https://s.id/1x0Kv)
    
* [https://phpunit.readthedocs.io/en/9.5/assertions.html](https://s.id/1x0Kg)
    
* [https://webkul.com/blog/object-mocking-in-unit-test-magento-2-open-source-and-adobe-commerce/](https://s.id/1x0JD)
