如何在PHPUnit测试中显示底层测试方法



我有一个测试套件,里面有很多测试。这是一个中号的:

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

谢谢你的建议。

我的方法是结合 @covers 标签和自定义结果打印机

你应该使用@covers标签来生成更有意义的代码覆盖,特别是在更大的测试套件中,重要的是要确保只有假定测试一个方法的测试才真正为它生成覆盖。

我知道你的问题与保险范围无关,但我们马上就会讨论这个问题。也许仅仅使用那个注释对你来说就足够了,因为每个没有专门测试的方法都会显示0%的覆盖率,不管你是否运行所有的集成测试等等。


收集所需信息的自定义结果侦听器

实现当然可以调整,我只是想生产一些工作得相当不错的东西来展示这个概念,希望给你一些你可以适应的东西。

代码是alpha,因为我只写了这个问题,但它适用于当前的phpunit,我认为我粘贴了你需要的一切。

结果:

 --- myClass ---
-- myClass::a --
  ok   - myClassTest::testAone
  fail - myClassTest::testAtwoFails
-- myClass::b --
  ok   - myClassTest::testB
-- myClass::untested --
  !! Method untested !!

我希望这符合您想要的输出。在下面的代码中可以很容易地更改格式。

它为您要测试的每个类打印这段信息(一个空的就足够了!)

如果一个测试@覆盖多个方法,它将显示每一个方法


Test

下的类
<?php
class myClass {

    public function a() {
        return 1;
    }
    public function b() {
        return 2;
    }
    public function untested() {
        return 3;
    }
}

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 "nn --- $classUnderTest --- nn";
            foreach($methods as $method => $testCaseStrings) {
                echo "-- $classUnderTest::$method -- n";
                if($testCaseStrings == array()) {
                    echo "  !! Method untested !!n";
                    continue;
                }
                foreach($testCaseStrings as $testCaseString) {
                    echo "  $testCaseStringn";
                }
                echo "n";
            }
        }
    }
}

相关内容

最新更新