Как отобразить проверенный метод в тестах PHPUnit? - PullRequest
7 голосов
/ 15 июля 2011

У меня есть наборы тестов с большим количеством тестов в них.Вот среднего размера:

ok  4 - CommodityBasketTest::testStartsOutEmpty
ok  5 - CommodityBasketTest::testCanAddACommodity
ok  6 - CommodityBasketTest::testWillAddOneCommodityByDefault
ok  7 - CommodityBasketTest::testCannotAddACommodityWithAnNonNumericQuantity
ok  8 - CommodityBasketTest::testAddingTheSameCommodityWillIncreaseItsQuantity
ok  9 - CommodityBasketTest::testMultipleCommodityCanBeAdded
ok 10 - CommodityBasketTest::testTakingFromAnEmptyBasketWontWork
ok 11 - CommodityBasketTest::testTakesFirstCommodityFromTheBasket
ok 12 - CommodityBasketTest::testCanRetrieveASpecificCommodity
ok 13 - CommodityBasketTest::testWillThrowExceptionOnMissingCommodity
ok 14 - CommodityBasketTest::testReturnsZeroWorthForEmptyBaskets
ok 15 - CommodityBasketTest::testReturnsProperWorthOfACommodity
ok 16 - CommodityBasketTest::testWillAccuratelyReturnStatistics

Как я могу настроить PHPUnit так, чтобы я мог каким-то образом отобразить базовый тестируемый метод, как он у меня есть в вставке ??Я гибкий на выходе;Я просто хотел бы знать, что, например, CommodityBasketTest::testReturnsZeroWorthForEmptyBaskets тестирует CommodityBasket::getValuation().

Вот что я хотел бы:

-- CommodityBasket::__construct() --
ok  4 - CommodityBasketTest::testStartsOutEmpty

-- CommodityBasket::add() --
ok  5 - CommodityBasketTest::testCanAddACommodity
ok  6 - CommodityBasketTest::testWillAddOneCommodityByDefault
ok  7 - CommodityBasketTest::testCannotAddACommodityWithAnNonNumericQuantity
ok  8 - CommodityBasketTest::testAddingTheSameCommodityWillIncreaseItsQuantity
ok  9 - CommodityBasketTest::testMultipleCommodityCanBeAdded

-- CommodityBasket::take() --
ok 10 - CommodityBasketTest::testTakingFromAnEmptyBasketWontWork
ok 11 - CommodityBasketTest::testTakesFirstCommodityFromTheBasket
ok 12 - CommodityBasketTest::testCanRetrieveASpecificCommodity
ok 13 - CommodityBasketTest::testWillThrowExceptionOnMissingCommodity

-- CommodityBasket::getValuation() --
ok 14 - CommodityBasketTest::testReturnsZeroWorthForEmptyBaskets
ok 15 - CommodityBasketTest::testReturnsProperWorthOfACommodity

-- CommodityBasket::dumpStats() --
ok 16 - CommodityBasketTest::testWillAccuratelyReturnStatistics

Спасибо за ваши предложения.

1 Ответ

13 голосов
/ 19 июля 2011

Мой подход - комбинация тега @covers и пользовательского принтера .

Вы должны использовать тег @covers в любом случае, чтобы генерировать более значимое покрытие кода, особенно в больших наборах тестов. Важно убедиться, что только тесты, которые предполагаются для тестирования метод действительно генерирует покрытие для него.

Я знаю, что ваш вопрос не связан с освещением, но мы вернемся к этому через минуту. И, может быть, вам достаточно просто использовать эту аннотацию, поскольку каждый метод, для которого нет выделенного теста, будет показывать покрытие в 0% независимо от того, выполняете ли вы все интеграционные тесты и т. Д.


Пользовательский обработчик результатов для сбора необходимой информации

Реализация может быть настроена непринужденно, я просто хотел создать что-то, что работает достаточно хорошо, чтобы показать концепцию и, надеюсь, дать вам то, что вы можете адаптировать.

Код альфа, поскольку я написал его только для этого вопроса, но он работает с текущим phpunit, и я думаю, что вставил все, что вам нужно.

Результат:

 --- myClass ---

-- myClass::a --
  ok   - myClassTest::testAone
  fail - myClassTest::testAtwoFails

-- myClass::b --
  ok   - myClassTest::testB

-- myClass::untested --
  !! Method untested !!

Надеюсь, это соответствует желаемому результату. Форматирование можно легко изменить в приведенном ниже коде.

Печатает эту информацию для каждого класса, для которого у вас есть тест (достаточно пустого!)

Если один из тестов @ покрывает несколько методов, он появится для КАЖДОГО из этих методов


Тестируемый класс

<?php

class myClass {



    public function a() {
        return 1;
    }

    public function b() {
        return 2;
    }

    public function untested() {
        return 3;
    }
}

The Testcase

<?php

require_once("myClass.php");

class myClassTest extends PHPUnit_Framework_TestCase {

    /**
     * @covers a
     */
    public function testAone() {
        $sut = new myClass();
        $this->assertSame(1, $sut->a());
    }

    /**
     * @covers a
     */
    public function testAtwoFails() {
        $sut = new myClass();
        $this->assertSame("error", $sut->a());

    }

    /**
     * @covers b
     */
    public function testB() {
        $sut = new myClass();
        $this->assertSame(2, $sut->b());
    }

}

phpunit.xml, необходимый для регистрации тестового слушателя!

<phpunit>
    <listeners>
        <listener class="ResultPrinterListener" file="./ResultPrinterListener.php"></listener>
    </listeners>
</phpunit>

Результирующий принтер

<?php

class ResultPrinterListener implements PHPUnit_Framework_TestListener {

    protected $suites = array();

    public function addError(PHPUnit_Framework_Test $test, Exception $e, $time) {}
    public function addFailure(PHPUnit_Framework_Test $test, PHPUnit_Framework_AssertionFailedError $e, $time) {}
    public function addIncompleteTest(PHPUnit_Framework_Test $test, Exception $e, $time) {}
    public function addSkippedTest(PHPUnit_Framework_Test $test, Exception $e, $time) {}
    public function startTest(PHPUnit_Framework_Test $test) {}
    public function endTest(PHPUnit_Framework_Test $test, $time) {}
    public function startTestSuite(PHPUnit_Framework_TestSuite $suite) {}

    public function endTestSuite(PHPUnit_Framework_TestSuite $suite) {
        $this->suites[] = $suite;
    }

    public function __destruct() {
        $tests = array();
        foreach($this->suites as $suite) {
            foreach($suite->tests() as $test) {
                if(!$test instanceOf PHPUnit_Framework_TestCase) {
                    continue;
                }

                $testClass = get_class($test);
                $classUnderTest = substr($testClass, 0, -4);  // just cutting the "Test" for now
                /**
                 * Create an array structue
                 *   array[ClassUnderTests][methodUnderTest][arrayOfTestMethodsThatTestThatMethod]
                 * Every method for a class you have at least one test for will show up here for now
                 */
                if(!isset($tests[$classUnderTest])) {
                    if(!class_exists($classUnderTest)) {
                        echo "\nCan't find matching class '$classUnderTest' for test class $testClass!\n";
                    }
                    $class = new ReflectionClass($classUnderTest);
                    foreach($class->getMethods() as $method) {
                        $tests[$classUnderTest][$method->getName()] = array();
                    }
                }
                $annotations = $test->getAnnotations();
                if(!isset($annotations["method"]["covers"])) {
                    continue;
                }

                foreach($annotations["method"]["covers"] as $functionUnderTest) {

                    $statusLine = "";
                    $status = $test->getStatus();
                    if($status == PHPUnit_Runner_BaseTestRunner::STATUS_FAILURE) {
                        $statusLine .= "fail - ";
                    } else if($status == PHPUnit_Runner_BaseTestRunner::STATUS_SKIPPED) {
                        $statusLine .= "skip - ";
                    } else if($status == PHPUnit_Runner_BaseTestRunner::STATUS_INCOMPLETE) {
                        $statusLine .= "inc  - ";
                    } else {
                        $statusLine .= "ok   - ";
                    }
                    $statusLine .= $testClass."::".$test->getName();
                    $tests[$classUnderTest][$functionUnderTest][] = $statusLine;
               }
            }
        }
        foreach($tests as $classUnderTest => $methods) {
            echo "\n\n --- $classUnderTest --- \n\n";
            foreach($methods as $method => $testCaseStrings) {
                echo "-- $classUnderTest::$method -- \n";
                if($testCaseStrings == array()) {
                    echo "  !! Method untested !!\n";
                    continue;
                }
                foreach($testCaseStrings as $testCaseString) {
                    echo "  $testCaseString\n";
                }
                echo "\n";
            }

        }
    }

}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...