phpunitAan de slag met phpunit


Opmerkingen

Deze sectie geeft een overzicht van wat phpunit is en waarom een ontwikkelaar het misschien wil gebruiken.

Het moet ook alle grote onderwerpen binnen phpunit vermelden en naar de gerelateerde onderwerpen verwijzen. Aangezien de documentatie voor phpunit nieuw is, moet u mogelijk eerste versies van die gerelateerde onderwerpen maken.

versies

Versie Ondersteuning eindigt Ondersteund in die PHP-versies Publicatiedatum
5.4 2016/08/05 PHP 5.6, PHP 7. 2016/06/03
4.8 2017/02/03 PHP 5.3, PHP 5.4, PHP 5.5 en PHP 5.6. 2015/08/07

Maak de eerste PHPUnit-test voor onze klas

Stel je voor dat we een klasse Math.php met logica voor het berekenen van fiobanacci en faculteiten. Iets zoals dit:

<?php    
class Math {
    public function fibonacci($n) {
        if (is_int($n) && $n > 0) {
            $elements = array();
            $elements[1] = 1;
            $elements[2] = 1;
            for ($i = 3; $i <= $n; $i++) {
                $elements[$i] = bcadd($elements[$i-1], $elements[$i-2]);
            }
            return $elements[$n];
        } else {
            throw new 
                InvalidArgumentException('You should pass integer greater than 0');
        }
    }

    public function factorial($n) {
        if (is_int($n) && $n >= 0) {
            $factorial = 1;
            for ($i = 2; $i <= $n; $i++) {
                $factorial *= $i;
            }
            return $factorial;
        } else {
            throw new 
                InvalidArgumentException('You should pass non-negative integer');
        }
    }
}
 

De eenvoudigste test

We willen de logica van methoden fibonacci en factorial testen. Laten we het bestand MathTest.php in dezelfde map maken met Math.php . In onze code kunnen we verschillende beweringen gebruiken . De eenvoudigste code zal er ongeveer zo assertEquals (we gebruiken alleen assertEquals en assertTrue ):

<?php
require 'Math.php';

use PHPUNIT_Framework_TestCase as TestCase;
// sometimes it can be
// use PHPUnit\Framework\TestCase as TestCase;

class MathTest extends TestCase{
    public function testFibonacci() {
        $math = new Math();
        $this->assertEquals(34, $math->fibonacci(9));
    }

    public function testFactorial() {
        $math = new Math();
        $this->assertEquals(120, $math->factorial(5));
    }

    public function testFactorialGreaterThanFibonacci() {
        $math = new Math();
        $this->assertTrue($math->factorial(6) > $math->fibonacci(6));
    }
}
 

We kunnen deze test uitvoeren vanaf de console met opdracht phpunit MathTest en de uitvoer is:

    PHPUnit 5.3.2 by Sebastian Bergmann and contributors.

...                                                                 3 / 3 (100%)

Time: 88 ms, Memory: 10.50Mb

OK (3 tests, 3 assertions)
 

DataProviders gebruiken

Een testmethode kan willekeurige argumenten accepteren. Deze argumenten moeten worden verstrekt door een gegevensprovider- methode. De te gebruiken gegevensprovider-methode wordt gespecificeerd met behulp van de annotatie @dataProvider . :

<?php
require 'Math.php';

use PHPUNIT_Framework_TestCase as TestCase;
// sometimes it can be
// use PHPUnit\Framework\TestCase as TestCase;

class MathTest extends TestCase {
    /**
     * test with data from dataProvider
     * @dataProvider providerFibonacci
     */
    public function testFibonacciWithDataProvider($n, $result) {
        $math = new Math();
        $this->assertEquals($result, $math->fibonacci($n));
    }

    public function providerFibonacci() {
        return array(
            array(1, 1),
            array(2, 1),
            array(3, 2),
            array(4, 3),
            array(5, 5),
            array(6, 8),
        );
    }
}
 

We kunnen deze test uitvoeren vanaf de console met opdracht phpunit MathTest en de uitvoer is:

    PHPUnit 5.3.2 by Sebastian Bergmann and contributors.

......                                                              6 / 6 (100%)

Time: 97 ms, Memory: 10.50Mb

OK (6 tests, 6 assertions)


<?php
require 'Math.php';
use PHPUNIT_Framework_TestCase as TestCase;
// sometimes it can be
// use PHPUnit\Framework\TestCase as TestCase;
 

Test uitzonderingen

We kunnen testen of een uitzondering wordt gegenereerd door de te testen code met de methode expectException() . In dit voorbeeld voegen we ook één mislukte test toe om de console-uitvoer voor mislukte tests te tonen.

<?php
require 'Math.php';
use PHPUNIT_Framework_TestCase as TestCase;
// sometimes it can be
// use PHPUnit\Framework\TestCase as TestCase;

class MathTest extends TestCase {
    public function testExceptionsForNegativeNumbers() {
        $this->expectException(InvalidArgumentException::class);
        $math = new Math();
            $math->fibonacci(-1);
    }

    public function testFailedForZero() {
        $this->expectException(InvalidArgumentException::class);
        $math = new Math();
        $math->factorial(0);
    }
}
 

We kunnen deze test uitvoeren vanaf de console met opdracht phpunit MathTest en de uitvoer is:

        PHPUnit 5.3.2 by Sebastian Bergmann and contributors.

.F                                                                  2 / 2 (100%)

Time: 114 ms, Memory: 10.50Mb

There was 1 failure:

1) MathTest::testFailedForZero
Failed asserting that exception of type "InvalidArgumentException" is thrown.

FAILURES!
Tests: 2, Assertions: 2, Failures: 1.
 

SetUp en TearDown

Ook ondersteunt PHPUnit het delen van de installatiecode. Voordat een testmethode wordt uitgevoerd, wordt een sjabloonmethode met de naam setUp () aangeroepen. setUp() is waar u de objecten maakt waartegen u gaat testen. Zodra de testmethode is uitgevoerd, of deze is geslaagd of mislukt, wordt een andere sjabloonmethode met de naam tearDown() aangeroepen. tearDown() is waar u de objecten opschoont waartegen u hebt getest.

<?php
require 'Math.php';

use PHPUNIT_Framework_TestCase as TestCase;
// sometimes it can be
// use PHPUnit\Framework\TestCase as TestCase;

class MathTest extends TestCase {
    public $fixtures;
    protected function setUp() {
        $this->fixtures = [];
    }

    protected function tearDown() {
        $this->fixtures = NULL;
    }

    public function testEmpty() {
        $this->assertTrue($this->fixtures == []);
    }
}
 

Meer informatie

Er zijn veel meer geweldige mogelijkheden van PHPUnit die u in uw test kunt gebruiken. Zie voor meer informatie in de officiële handleiding

Voorbeeld van PHPUNIT met APItest met Stub And Mock

Klasse waarvoor u een unit-testcase maakt. class Authorization {

/* Observer so that mock object can work. */    
 public function attach(Curl $observer)
{
    $this->observers = $observer;
}

/* Method for which we will create test */
public  function postAuthorization($url, $method) {
    
    return $this->observers->callAPI($url, $method);
}
 

}

Nu wilden we geen externe interactie van onze testcode, dus moeten we een mock-object maken voor de callAPI-functie, omdat deze functie in feite externe url via curl aanroept. class AuthorizationTest extends PHPUnit_Framework_TestCase {

protected $Authorization;

/**
 * This method call every time before any method call.
 */
protected function setUp() {
    $this->Authorization = new Authorization();
}

/**
 * Test Login with invalid user credential
 */
function testFailedLogin() {

    /*creating mock object of Curl class which is having callAPI function*/
    $observer = $this->getMockBuilder('Curl')
                     ->setMethods(array('callAPI'))
                     ->getMock();

    /* setting the result to call API. Thus by default whenver call api is called via this function it will return invalid user message*/
    $observer->method('callAPI')
            ->will($this->returnValue('"Invalid user credentials"'));

    /* attach the observer/mock object so that our return value is used */
    $this->Authorization->attach($observer);

    /* finally making an assertion*/
    $this->assertEquals('"Invalid user credentials"',           $this->Authorization->postAuthorization('/authorizations', 'POST'));
}
 

}

Hieronder staat de code voor curl class (slechts een voorbeeld) class Curl{ function callAPI($url, $method){

    //sending curl req
}
 

}

Minimale voorbeeldtest

Gegeven een eenvoudige PHP-klasse:

class Car
{
    private $speed = 0;

    public getSpeed() {
        return $this->speed;
    }

    public function accelerate($howMuch) {
        $this->speed += $howMuch;
    }
}
 

U kunt een PHPUnit-test schrijven die het gedrag van de te testen klasse test door de openbare methoden aan te roepen en te controleren of deze naar verwachting werken:

class CarTest extends PHPUnit_Framework_TestCase
{
    public function testThatInitalSpeedIsZero() {
        $car = new Car();
        $this->assertSame(0, $car->getSpeed());
    }

    public function testThatItAccelerates() {
        $car = new Car();
        $car->accelerate(20);
        $this->assertSame(20, $car->getSpeed());
    }

    public function testThatSpeedSumsUp() {
        $car = new Car();
        $car->accelerate(30);
        $car->accelerate(50);
        $this->assertSame(80, $car->getSpeed());
    }
}
 

Belangrijke onderdelen:

  1. Testklasse moet afkomstig zijn van PHPUnit_Framework_TestCase.
  2. Elke testfunctienaam moet beginnen met het voorvoegsel 'test'
  3. Gebruik de functies $this->assert... om de verwachte waarden te controleren.

Spottende lessen

De praktijk om een object te vervangen door een testdubbel die verwachtingen verifieert, bijvoorbeeld door te beweren dat een methode is aangeroepen, wordt mocking genoemd.

Laten we aannemen dat we SomeService moeten testen.

class SomeService
{
    private $repository;
    public function __construct(Repository $repository)
    {
        $this->repository = $repository;
    }

    public function methodToTest()
    {
        $this->repository->save('somedata');
    }
}   
 

En we willen testen of methodToTest save methode van repository aanroept. Maar we willen de repository niet echt instantiëren (of misschien is Repository slechts een interface).

In dit geval kunnen we Repository bespotten.

use PHPUnit\Framework\TestCase as TestCase;

class SomeServiceTest extends TestCase
{    
    /**
     * @test
     */
    public function testItShouldCallRepositorySavemethod()
    {
        // create an actual mock
        $repositoryMock = $this->createMock(Repository::class);

        $repositoryMock->expects($this->once()) // test if method is called only once
             ->method('save')                   // and method name is 'save'
             ->with('somedata');                // and it is called with 'somedata' as a parameter

        $service = new SomeService($repositoryMock);
        $service->someMethod();
    }
}