PROGRAMMING

m9/ PHP
REMEMBERS




Last update:   23-07-2021

Test doubles

! To avoid creating all dependencies when testing, will use test doubles. Test doubles are easier to create with interfaces instead of classes. Symfony provides such interfaces for core objects. Let's modify the framework to use interfaces.
 
// src/Simplex/Framework.php

namespace Simplex;

use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\ComponentRouting\Exception\ResourceNotFoundException;

use Symfony\Component\Routing\Matcher\UrlMatcherInterface; // Look Here
use Symfony\Component\HttpKernel\Controller\ControllerResolverInterface;
use Symfony\Component\HttpKernel\Controller\ArgumentResolverInterface;

Class Framework
{
    private $matcher;
    private $controllerResolver;
    private $argumentResolver;

    public function __construct(UrlMatcherInterface $matcher, 
                        ControllerResolverInterface $controllerResolver,
                            ArgumentResolverInterface $argumentResolver)
    {
        $this->matcher = $matcher;
        $this->controllerResolver = $controllerResolver;
        $this->argumentResolver = $argumentResolver;
    }

...
... 16 lines
 

Test 404

This test simulates a request that doesn't match any route. The match() method returns a ResourceNotFoundException exception. We are testing that our framework converts this exception to a 404 response. Create a PHPUnit configuration file in app root directory: phpunit.xml.dist Execute this test by running phpunit in app root directory.
 
// tests/Simplex/Tests/FrameworkTest.php

namespace Simplex\Tests;

use PHPUnit\Framework\TestCase;
use Simplex\Framework;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Controller\ArgumentResolverInterface;
use Symfony\Component\HttpKernel\Controller\ControllerResolverInterface;
use Symfony\Component\Routing\RequestContext;
use Symfony\Component\Routing\Matcher\UrlMatcherInterface;
use Symfony\Component\Routing\Exception\ResourceNotFoundException;

class FrameworkTest extends TestCase
{
    public function testNotFoundHandling()
    {
        $matcher = $this->createMock(UrlMatcherInterface::class);
        $matcher
            ->expects($this->once())
            ->method('match')
            ->will($this->throwException(
                    new ResourceNotFoundException() // Look Here
            ))
        ;
        $controllerResolver = $this->createMock(
            ControllerResolverInterface::class
        );
        $argumentResolver = $this->createMock(
            ArgumentResolverInterface::class
        );
        $framework = new Framework(
            $matcher, $controllerResolver, $argumentResolver
        );
        $response = $framework->handle(new Request());
        $this->assertEquals(404, $response->getStatusCode());
    }
}
... 29 lines
 
 
<?xml version="1.0" encoding="UTF-8"?>
<phpunit
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/5.1/phpunit.xsd"
    backupGlobals="false"
    colors="true"
    bootstrap="vendor/autoload.php">
    <testsuites>
        <testsuite name="Test Suite">
            <directory>./tests</directory>
        </testsuite>
    </testsuites>

    <filter>
        <whitelist processUncoveredFilesFromWhitelist="true">
            <directory suffix=".php">./src</directory>
        </whitelist>
    </filter>
</phpunit>
... 12 lines
 
 
./vendor/bin/phpunit --testdox

Test 200

Let's add a test for when we have a proper Response. We simulate a route that match and returns a simple controller. We check that the status is 200 and that its content is one we have in the controller.
 
// tests/Simplex/Tests/FrameworkTest.php

namespace Simplex\Tests;

use PHPUnit\Framework\TestCase;
use Simplex\Framework;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Controller\ArgumentResolverInterface;
use Symfony\Component\HttpKernel\Controller\ControllerResolverInterface;
use Symfony\Component\HttpKernel\Controller\ArgumentResolver;
use Symfony\Component\HttpKernel\Controller\ControllerResolver;
use Symfony\Component\Routing\RequestContext;
use Symfony\Component\Routing\Matcher\UrlMatcherInterface;
use Symfony\Component\Routing\Exception\ResourceNotFoundException;

class FrameworkTest extends TestCase
{
    // 404
    public function testNotFoundHandling()
    {
        $matcher = $this->createMock(UrlMatcherInterface::class);
        $matcher
            ->expects($this->once())
            ->method('match')
            ->will($this->throwException(
                    new ResourceNotFoundException() // Look Here - 404
            ))
        ;
        $controllerResolver = $this->createMock(
            ControllerResolverInterface::class
        );
        $argumentResolver = $this->createMock(
            ArgumentResolverInterface::class
        );
        $framework = new Framework(
            $matcher, $controllerResolver, $argumentResolver
        );
        $response = $framework->handle(new Request());

            //fwrite(STDERR, $response->getStatusCode() . "\n\r"); die;
        $this->assertEquals(404, $response->getStatusCode());
    }
    
    // 200
    public function testControllerResponse()
    {
        $matcher = $this->createMock(UrlMatcherInterface::class);
        $matcher
            ->expects($this->once())
            ->method('match')
            ->will($this->returnValue([
                '_route' => '/isEven/{no}',
                'no' => 2,
                '_controller' =>
                    'NumberChecker\Controller\CheckNumberController::index'
            ]))
        ;
        $controllerResolver = new ControllerResolver();
        $argumentResolver = new ArgumentResolver();
        $framework = new Framework(
            $matcher, $controllerResolver, $argumentResolver
        );
        $response = $framework->handle(new Request());

            //fwrite(STDERR, $response->getStatusCode() . "\n\r"); die;
        $this->assertEquals(200, $response->getStatusCode());
        $this->assertStringContainsString(
            'Yes, the number is even!', $response->getContent()
        );
    }
}
... 59 lines
 
Framework v7.0
Questions    
Dispatcher