3
\$\begingroup\$

I have been reading up on TDD and it's something I genuinely want to learn and be good at. This is something I haven't been doing as a developer and I thought it's about time I get into it.

These are two custom helper Facade classes in a Laravel 5.5 REST API project:

XmlXsdValidator Facade - https://pastebin.com/Nc7hsjic

S3 Facade - https://pastebin.com/tMxprRy2

Below are two Unit tests I've wrote and they run fine:

enter image description here

I am looking for criticism and tips on how to write better tests, which in turn will help me write good/readable/re-usable/maintainable code.

XmlXsdValidatorFacadeTest:

<?php

namespace Tests\Unit;

use Tests\TestCase;
use ArgumentCountError;
use InvalidArgumentException;
use UnexpectedValueException;
use App\Facades\XmlXsdValidator;

class XmlXsdValidatorFacadeTest extends TestCase
{
    protected function setUp()
    {
        parent::setUp();

        $this->validXml = file_get_contents(storage_path('data/test/Valid_ListBucketResult.xml'));
        $this->invalidXml = file_get_contents(storage_path('data/test/Invalid_ListBucketResult.xml'));
        $this->xsdPath = config('myApp.listBucketResultXsdPath');
    }

    public function testShouldCheckIfAllArgumentsArePresent()
    {
        $this->expectException(ArgumentCountError::class);
        XmlXsdValidator::validate();
    }

    public function testShouldCheckIfXmlStringArgumentIsPresent()
    {
        $this->expectException(InvalidArgumentException::class);
        XmlXsdValidator::validate('', null);
    }

    public function testShouldCheckIfXsdSchemaPathArgumentIsPresent()
    {
        $this->expectException(InvalidArgumentException::class);
        XmlXsdValidator::validate(null, '');
    }

    public function testShouldCheckIfInvalidXmlStringIsSupplied()
    {
        $this->expectException(UnexpectedValueException::class);
        XmlXsdValidator::validate('invalid-data', $this->xsdPath);
    }

    public function testShouldFailXmlXsdValidationWhenXmlDataDoesNotMatchXsdSchema()
    {
        $this->expectException(UnexpectedValueException::class);
        XmlXsdValidator::validate($this->invalidXml, $this->xsdPath);
    }

    public function testShouldSucceedXmlXsdValidationWhenXmlDataMatchesXsdSchema()
    {
        $this->assertTrue(XmlXsdValidator::validate($this->validXml, $this->xsdPath));
    }
}

S3FacadeTest:

<?php

namespace Tests\Unit;

use App\Facades\S3;
use Illuminate\Support\Facades\Cache;
use Tests\TestCase;
use InvalidArgumentException;

class S3FacadeTest extends TestCase
{
    protected function setUp()
    {
        parent::setUp();

        $this->originalConfig = config('myApp');
        $this->testCustomerFiles = [
            'a4a06bb0-3fbe-40bd-9db2-f68354ba742f.json',
            'be0438bf-8b0d-4c57-913d-fcafb0bb41f0.json',
            'be9b2a8b-e846-4365-8d5f-0fca4ef9aefb.json',
        ];
        $this->testCustomerGuid = 'a4a06bb0-3fbe-40bd-9db2-f68354ba742f';
        $this->testCustomerAccounts = [
            '861fc585-3313-4928-891d-c8711dfe3f8a',
            '0391a1cc-2c00-47b8-9880-aa9fe96bef51',
            '8a28f09a-c234-4a95-b1e0-cdbc68979d0a'
        ];
    }

    public function testShouldCheckIfValidS3BucketUrlIsPresentInApplicationConfig()
    {
        $this->expectException(InvalidArgumentException::class);
        config(['myApp.s3BucketUrl' => '']);
        S3::listCustomerFiles();
    }

    public function testShouldReturnCachedArrayOfCustomerFilesInCorrectFormat()
    {
        config($this->originalConfig);
        $customerFiles = S3::listCustomerFiles();

        $this->assertTrue(is_array($customerFiles));
        $this->assertTrue($this->arrays_are_similar($customerFiles, array_flip($this->testCustomerFiles)));
        $this->assertCount(3, $customerFiles);
        foreach ($this->testCustomerFiles as $customerFile) {
            $this->assertArrayHasKey($customerFile, $customerFiles);
        }

        $this->assertTrue(Cache::has('Customer_Files'));
        $cachedCustomerFiles = Cache::get('Customer_Files');
        $this->assertTrue(is_array($cachedCustomerFiles));
        $this->assertTrue($this->arrays_are_similar($cachedCustomerFiles, array_flip($this->testCustomerFiles)));
        $this->assertCount(3, $cachedCustomerFiles);
        foreach ($this->testCustomerFiles as $customerFile) {
            $this->assertArrayHasKey($customerFile, $cachedCustomerFiles);
        }
    }

    public function testShouldReturnNonCachedArrayOfCustomerFilesInCorrectFormat()
    {
        Cache::clear();

        config($this->originalConfig);
        config(['myApp.cacheMins' => 0]);
        $customerFiles = S3::listCustomerFiles();

        $this->assertTrue(is_array($customerFiles));
        $this->assertTrue($this->arrays_are_similar($customerFiles, array_flip($this->testCustomerFiles)));
        $this->assertCount(3, $customerFiles);
        foreach ($this->testCustomerFiles as $customerFile) {
            $this->assertArrayHasKey($customerFile, $customerFiles);
        }

        $this->assertFalse(Cache::has('Customer_Files'));
    }

    public function testShouldReturnCachedArrayOfCustomerAccountsInCorrectFormat()
    {
        config($this->originalConfig);
        $customerAccounts = S3::loadCustomerAccounts($this->testCustomerGuid);

        $this->assertTrue(is_array($customerAccounts));
        $this->assertCount(100, $customerAccounts);
        foreach ($this->testCustomerAccounts as $customerAccountGuid) {
            $this->assertTrue(in_array($customerAccountGuid, $customerAccounts));
        }

        $this->assertTrue(Cache::has(sprintf('Customer_%s_Accounts', $this->testCustomerGuid)));
        $cachedCustomerAccounts = Cache::get(sprintf('Customer_%s_Accounts', $this->testCustomerGuid));
        foreach ($cachedCustomerAccounts as $cachedCustomerAccountGuid) {
            $this->assertTrue(in_array($cachedCustomerAccountGuid, $cachedCustomerAccounts));
            $this->assertTrue(Cache::has(sprintf('Account_%s_Data', $cachedCustomerAccountGuid)));
            $cachedAccountData = Cache::get(sprintf('Account_%s_Data', $cachedCustomerAccountGuid));
            $this->assertTrue(is_object($cachedAccountData));
            $this->assertObjectNotHasAttribute('id', $cachedAccountData);
            $this->assertObjectHasAttribute('firstname', $cachedAccountData);
            $this->assertObjectHasAttribute('lastname', $cachedAccountData);
            $this->assertObjectHasAttribute('email', $cachedAccountData);
            $this->assertObjectHasAttribute('telephone', $cachedAccountData);
            $this->assertObjectHasAttribute('balance', $cachedAccountData);
        }
    }

    public function testShouldReturnNonCachedArrayOfCustomerAccountsInCorrectFormat()
    {
        Cache::clear();

        config($this->originalConfig);
        config(['myApp.cacheMins' => 0]);
        $customerAccounts = S3::loadCustomerAccounts($this->testCustomerGuid);

        $this->assertTrue(is_array($customerAccounts));
        $this->assertCount(100, $customerAccounts);
        foreach ($this->testCustomerAccounts as $customerAccountGuid) {
            $this->assertTrue(in_array($customerAccountGuid, $customerAccounts));
        }

        $this->assertFalse(Cache::has(sprintf('Customer_%s_Accounts', $this->testCustomerGuid)));
    }

    /**
     * Determine if two associative arrays are similar.
     * @author https://stackoverflow.com/a/3843768/2332336
     *
     * @param array $a
     * @param array $b
     * @return bool
     */
    function arrays_are_similar(array $a, array $b) {
        if (count(array_diff_assoc($a, $b))) {
            return false;
        }
        foreach($a as $k => $v) {
            if ($v !== $b[$k]) {
                return false;
            }
        }
        return true;
    }
}
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.