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\$

0

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.