簡體   English   中英

如何在 PHP 中為接口編寫測試

[英]How to write tests for an Interface in PHP

如果我正在編寫一個接口,我通常會指定實現應該公開的行為。 為了確保這種行為,應該針對這個接口編寫測試。 我如何最好地編寫和組織這些測試,以便實現的作者可以輕松地使用它們來確保他們的實現滿足要求? 是某種擴展(編寫子類)接口的方法測試要走的路還是我實現了一些像工廠這樣的設計模式?

我明白為什么人們告訴你你不需要測試接口。 但這不是你要問的。 您需要一種更簡單的方法來為實現某個接口的多個類執行相同的單元測試。 我使用@dataProvider注釋(PHPUnit,是的)來做到這一點。

假設你有這些類:

interface Shape {
    public function getNumberOfSides();
}

class Triangle implements Shape {
    private $sides = 3;
    
    public function getNumberOfSides() {
        return $this->sides;
    }
}

class Square implements Shape {
    private $sides = 4;
    
    public function getNumberOfSides() {
        return $this->sides;
    }
}

現在,您要測試Triangle實例的getNumberOfSides已定義並返回 3,而Square則返回 4。這就是您使用@dataProvider編寫此測試的@dataProvider

class ShapeTest extends PHPUnit_Framework_TestCase {

    /**
     * @dataProvider numberOfSidesDataProvider
     */
    public function testNumberOfSides(Shape $shape, $expectedSides){
        $this->assertEquals($shape->getNumberOfSides(), $expectedSides);
    }
    
    public function numberOfSidesDataProvider() {
        return array(
            array(new Square(), 5),
            array(new Triangle(), 3)
        );
    }
}

在這里運行 phpunit 會產生預期的輸出:

There was 1 failure:

1) ShapeTest::testNumberOfSides with data set #0 (Square Object (...), 5)
Failed asserting that 5 matches expected 4.

/tests/ShapeTest.php:12

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

您可以使用接口契約的一些基本測試創建一個抽象類。

考慮以下示例:

interface FactorialComputer {
    public function compute($input);
}

class RecursiveFactorialComputer implements FactorialComputer  {
    public function compute($input) {
        if ($input < 0) {
            throw new InvalidArgumentException(...);
        }

        if ($input == 0 || $input == 1) {
            return 1;
        }

        return $input * $this->compute($input - 1);
    }
}

class IterativeFactorialComputer implements FactorialComputer  {
    public function compute($input) {
        $result = 1;

        for ($i = 1; $i <= $input; $i++) {
            $result *= $i;
        }

        return $result;
    }
}

並對兩種實現進行測試:

abstract class AbstractFactorialComputerTest extends PHPUnit_Framework_TestCase {
    /**
     * @var FactorialComputer 
     */
    protected $instance;

    protected abstract function getComputerInstance();

    public function setUp() {
        $this->instance = $this->getComputerInstance;
    }

    /**
     * @expectedException InvalidArgumentException
     */
    public function testExceptionOnInvalidArgument() {
        $this->instance->compute(-1);
    }

    public function testEdgeCases()
    {
        $this->assertEquals(1, $this->instance->compute(0));
        $this->assertEquals(1, $this->instance->compute(1));
    }

    ...
}

class RecursiveFactorialComputerTest extends AbstractFactorialComputerTest
{
    protected abstract function getComputerInstance() {
        return new RecursiveFactorialComputer();
    }

    public function testComputeMethodCallsCount() {
        // get mock and test number of compute() calls
    }
}

class IterativeFactorialComputerTest extends AbstractFactorialComputerTest
{
    protected abstract function getComputerInstance() {
        return new IterativeFactorialComputer();
    }
}

使用這種方法,每個程序員都應該能夠為接口實現創建完整的單元測試。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM