phpunitKomma igång med phpunit


Anmärkningar

Det här avsnittet ger en översikt över vad phpunit är, och varför en utvecklare kanske vill använda den.

Det bör också nämna alla stora ämnen inom phpunit och koppla till de relaterade ämnena. Eftersom dokumentationen för phpunit är ny kan du behöva skapa initialversioner av relaterade ämnen.

versioner

Version Supporten slutar Stöds i dessa PHP-versioner Utgivningsdatum
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 och PHP 5.6. 2015/08/07

Skapa det första PHPUnit-testet för vår klass

Föreställ dig att vi har en klass Math.php med logik för att beräkna fiobanacci och faktornummer. Något som det här:

<?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');
        }
    }
}
 

Det enklaste testet

Vi vill testa logik metoder fibonacci och factorial . Låt oss skapa filen MathTest.php i samma katalog med Math.php . I vår kod kan vi använda olika påståenden . Den enklaste koden kommer att vara något så här (vi använder bara assertEquals och 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));
    }
}
 

Vi kan köra detta test från konsolen med kommandot phpunit MathTest och output kommer att vara:

    PHPUnit 5.3.2 by Sebastian Bergmann and contributors.

...                                                                 3 / 3 (100%)

Time: 88 ms, Memory: 10.50Mb

OK (3 tests, 3 assertions)
 

Använda dataproviders

En testmetod kan acceptera godtyckliga argument. Dessa argument ska tillhandahållas med en dataleverantörsmetod . Dataföretagsmetoden som ska användas specificeras med @dataProvider anteckningen. :

<?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),
        );
    }
}
 

Vi kan köra detta test från konsolen med kommandot phpunit MathTest och output kommer att vara:

    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;
 

Testundantag

Vi kan testa om ett undantag kastas av koden under testet med hjälp av metoden expectException() . I detta exempel lägger vi till ett misslyckat test för att visa konsolutgång för misslyckade test.

<?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);
    }
}
 

Vi kan köra detta test från konsolen med kommandot phpunit MathTest och output kommer att vara:

        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 och TearDown

PHPUnit stöder också delning av installationskoden. Innan en testmetod körs, anropas en mallmetod som heter setUp (). setUp() är där du skapar de objekt som du testar mot. När testmetoden har slutförts, oavsett om den lyckades eller misslyckades, anropas en annan mallmetod som heter tearDown() . tearDown() är där du rensar upp de objekt som du testade mot.

<?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 == []);
    }
}
 

Mer information

Det finns mycket fler stora möjligheter med PHPUnit som du kan använda i ditt test. För mer information se i officiell manual

Exempel på PHPUNIT med APItest med Stub And Mock

Klass för vilken du skapar enhetstestfall. 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 ville vi inte ha någon extern interaktion av vår testkod, så vi behöver skapa ett håravkast för callAPI-funktion eftersom den här funktionen faktiskt ringer extern url via curl. 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'));
}
 

}

Nedan class Curl{ function callAPI($url, $method){ koden för curl class (bara ett exempel) class Curl{ function callAPI($url, $method){

    //sending curl req
}
 

}

Minsta exempeltest

Med en enkel PHP-klass:

class Car
{
    private $speed = 0;

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

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

Du kan skriva ett PHPUnit-test som testar beteendet hos klassen som testas genom att ringa de offentliga metoderna och kontrollera om de fungerar som förväntat:

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());
    }
}
 

Viktiga delar:

  1. Testklassen måste härledas från PHPUnit_Framework_TestCase.
  2. Varje testfunktionsnamn bör börja med prefixet "test"
  3. Använd $this->assert... -funktioner för att kontrollera förväntade värden.

Hånliga klasser

Övningen av att ersätta ett objekt med en testdubbla som verifierar förväntningarna, till exempel att hävda att en metod har kallats, kallas hån.

Låt oss anta att vi har SomeService att testa.

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

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

Och vi vill testa om methodToTest verkligen kallar save metod för förvar. Men vi vill inte faktiskt instansera repository (eller kanske Repository är bara ett gränssnitt).

I det här fallet kan vi håna Repository .

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();
    }
}