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

2024-01-28

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

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 tests 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 http://www.phpunit.de/manual/current/en/appendixes.annotations.html#appendixes.annotations.covers标签和一个自定义结果打印机.

无论如何,您应该使用 @covers 标签来生成更有意义的代码覆盖率,特别是在更大的测试套件中,确保只有那些测试是很重要的supposed测试一个方法是否真正为其生成覆盖率。

我知道您的问题与覆盖范围无关,但我们稍后会讨论这个问题。也许仅使用该注释就足够了,因为无论您是否运行所有集成测试等,没有专用测试的每种方法都将显示 0% 覆盖率。


自定义结果监听器,用于收集您想要的信息

实现肯定可以调整,我只是想制作一些可以很好地展示概念的东西,并希望给你一些你可以适应的东西。

该代码是 alpha,因为我仅为该问题编写了它,但它适用于当前的 phpunit,我想我粘贴了您需要的所有内容。

结果:

 --- myClass ---

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

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

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

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

它会为您要测试的每一门课程打印这条信息(空的就足够了!)

如果测试 @covers 多种方法,它将显示其中的每一种方法


被测类

<?php

class myClass {



    public function a() {
        return 1;
    }

    public function b() {
        return 2;
    }

    public function untested() {
        return 3;
    }
}

测试用例

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

        }
    }

}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何在 PHPUnit 测试中显示底层测试方法? 的相关文章

  • 设置大型电子邮件通知系统有哪些方法?

    我的公司有一个用 PHP 构建的网站 我们使用内置的 PHP 电子邮件功能每天向订阅者发送数千封电子邮件 这是一个糟糕的主意 它堵塞了我们的服务器 并且需要几个小时才能完成整个批次 现在我已经研究过像 MailChimp 这样的群发邮件服务
  • 点击 %40 变为 %2540

    当单击包含 符号的链接时 该网址给我 40 这就是我想要的 但是一旦我点击它 一秒钟后它就在我点击后变成了 2540 单击是在电子邮件内 然后定向到网站 其中 40 更改为 2540 我怎样才能让它停止变化 它现在得到这样的参数 email
  • if/else 简写来定义变量

    我很难理解 if else 的 php 简写是如何描述的here https stackoverflow com questions 20233207 php if shorthand and echo in one line possib
  • Symfony2:为什么请求传递到受 Symfony2 中 AppCache 影响的 Kernel.Terminate EventListener

    在我的 Symfony2 2 应用程序中 我使用 onKernelTerminate EventListener 以便我可以在渲染响应后进行一些 繁重 处理 以便用户收到更快的响应时间 在我的控制器中 我在请求上设置了一个属性 以便当事件侦
  • Ajax 没有将我重定向到下一页

    我正在尝试将单击的图像的 ID 传递到下一页 当我开发代码时 它没有将我重定向到下一页 当我单击 F12 并检查网络中的 POST 时 它显示变量已正确传递到下一页 如附图所示 但它没有将我重定向到下一页 所以现在我知道变量在下一页中正确传
  • get url 重定向时 File_get_contents() 不起作用

    我正在使用的功能是 function http post url data data url http build query data data len strlen data url date default timezone set
  • 如何隐藏 URL 中的锚标记

    如何隐藏地址栏中以下链接 href 的哈希值 a href index php dev name 所以它会将我重定向到index php dev name 但我希望地址栏只显示index php 您可以使用 Javascript oncli
  • CodeIgniter 控制器 - JSON - AJAX

    我正在尝试通过 AJAX 使用 CodeIgniter 发送表单构建 并尝试使用 JSON 获取响应 但是 我只在打开开发人员选项卡时看到响应 我什至不确定这是否实际上是响应 因为它显示了两个 json 数据 它所显示的只是加载旋转器 然后
  • 在我的 index.php 中加载 CSS 和 JS 等资源时出现错误 403

    我使用的是 Linux Elementary OS 并在 opt 中安装了 lampp My CSS and JS won t load When I inspect my page through browser The console
  • 从类似 cronjob 的语法创建“下次运行时间”日期

    在我正在创建的应用程序中 用户可以安排重复任务 生成间隔模式的简单值是 Minute 0 59 90 each minute Hour 0 23 90 each hour Day of month 1 31 90 each day of m
  • 在 PHP 中比较两个对象的最快方法是什么?

    假设我有一个对象 在本例中为 User 对象 并且我希望能够使用单独的类来跟踪更改 用户对象不必以任何方式改变它的行为才能发生这种情况 因此 我的单独的类创建它的 干净 副本 将其存储在本地某个位置 然后可以将 User 对象与原始版本进行
  • 检查 PHP 中的字符串长度

    我有一个长度为 141 个字符的字符串 使用下面的代码我有一个if如果字符串大于或小于 140 则语句返回一条消息 libxml use internal errors TRUE dom new DOMDocument dom gt loa
  • 对 SimpleXML 数据进行排序和分组

    我正在对 XML 文件中的出版物数据进行排序和分组 我目前使用的方法效果很好大部分情况下 尽管我觉得有一种更有效的方法来完成我想要完成的任务 以下是目标节点的示例
  • Mysqli 更新抛出 Call to a member function bind_param() 错误[重复]

    这个问题在这里已经有答案了 我有一个 70 80 字段表单 需要插入到表中 因此我首先根据表单中的输入名称在数据库中创建了一个表 而不是手动创建一个巨大的插入语句 这是我使用的代码创建 更改表 function createTable ar
  • PHP 中的引用

    我正在编写一个自定义博客引擎 并且希望拥有类似于 Wordpress 的引用 我可以查看 WordPress 源代码 但我真的更喜欢某种教程 但到目前为止我还没有找到 有没有关于在 PHP5 中实现 trackbacks 或 pingbac
  • 如何通过ssh检查ubuntu服务器上是否存在php和apache

    如何通过ssh检查Ubuntu服务器上apache是 否安装了php和mysql 另外如果安装的话在哪个目录 如果安装了其他软件包 例如 lighttpd 那么它在哪里 确定程序是否已安装的另一种方法是使用which命令 它将显示您正在搜索
  • 从所有会话中注销

    我有一个注销选项 这是我的代码 session start session destroy setcookie key time 60 60 24 setcookie username time 60 60 24 我想添加另一个选项来注销所
  • 反向引用在 PHP 中不起作用

    最近我一直在研究 更多的是在实践中说实话 正则表达式 我注意到他的力量 我提出的这个要求 link https stackoverflow com questions 30380397 take the text up to a speci
  • 如何清除 APC 缓存而不使 Apache 崩溃?

    如果 APC 存储大量条目 清除它们会导致 httpd 崩溃 如果 apc clear cache user 花费的时间超过 phps max execution time 调用 apc clear cache 的脚本 将在之前被 php
  • ZF3/2 - 如何捕获 EVENT_DISPATCH 侦听器中引发的异常?

    有什么方法可以在 EVENT DISPATCH 监听器中抛出异常吗 class Module public function onBootstrap EventInterface event application event gt get

随机推荐

  • 将 R 数据帧从长格式转换为宽格式[重复]

    这个问题在这里已经有答案了 我有以下数据 df lt data frame left letters 1 4 right replicate 1 sample 0 100 12 rep TRUE 我看起来像这样 数字可能会有所不同 因为随机
  • Django 多态模型在 1.7 上进行迁移时出现问题

    我在我的模型中使用 Django 1 7 和 django polymorphic class ReferenceItem PolymorphicModel created at models DateTimeField date crea
  • MVP - Presenter 和服务层 - 在哪里声明服务层

    我正在通读为企业构建 Microsoft Net 解决方案我试图弄清楚有关演示者和服务层的一些事情 首先 我的 Presenter 需要调用驻留在服务层中的方法 例如initialize save 等 但是我在哪里放置对服务层的引用呢 它应
  • 如何使用 lambda 函数在列表/数组中查找具有匹配字母的字符串?

    我正在使用 lambda 函数 python 3 6 和 Mongodb atlas 在 mongodb 中 我有一个像这样的集合 集合名称配置文件 下面作为集合结构 id ObjectId 5db234df92b0ce00016932f3
  • [UITableView indexPathsForVisibleRows] 可能存在错误?

    我一直在我的代码中尝试这个 但它不起作用 NSArray paths aUITableView indexPathsForVisibleRows 返回一个空的 NSArray 但如果我在前一行中这样做 它就可以正常工作 这是一个框架错误吗
  • 字段成员与方法变量?

    最近我一直在思考类字段成员和方法变量之间的性能差异 我的确切意思是在下面的例子中 假设我们有一个DataContext对象为Linq2SQL class DataLayer ProductDataContext context new Pr
  • 时间:2019-01-17 标签:c#gridviewrowclick

    当我单击 GridView 中的一行时 我想使用从数据库获取的 ID 转到其他页面 在我的 RowCreated 事件中 我有以下行 e Row Attributes Add onClick ClientScript GetPostBack
  • 通过gradle构建项目时JVM空间耗尽

    通过gradle构建项目时收到错误消息 由于 JVM Tenured 空间已耗尽 守护进程即将到期 这意味着 JVM 没有足够的内存来编译 Java 文件 可以采取几个步骤 Run gradlew clean 这将删除所有内容 包括以前版本
  • 关于将 getchar() 返回值存储在 char 变量中

    I know以下代码已损坏 getchar 返回一个int not a char include
  • VBA XML 解析 - 循环子节点

    这是我第一次尝试使用 VBA 解析 XML 文件 因此我可能会遗漏一些显而易见的内容 我已经可以打印这个
  • 如何调试使用 rebar3 时运行的 Eunit 测试套件?

    我创建了一个release带有 rebar3 beta 4 的应用程序 添加了一些 eunit 测试并编写了一些代码 现在我必须调试一个测试用例 看看我必须添加什么才能使实现正常工作 我找到了一些关于使用的文章dbg从 Erlang 控制台
  • @property 和 @synthesize

    我对 Objective C 很陌生 两天了 当读到关于 synthesize 好像和我的理解有重叠 property 我以为我理解了 所以 一些细节需要在我的脑海中解决 这让我烦恼 如果我对差异的理解有误 请纠正我 property an
  • C# + 运算符调用 string.concat 函数? [复制]

    这个问题在这里已经有答案了 可能的重复 C 是否优化字符串文字的串联 https stackoverflow com questions 288794 does c sharp optimize the concatenation of s
  • AngularJS 中文本框更改时延迟调用函数

    似乎无法通过谷歌搜索如何完成此操作的示例 我已经成功创建了一个文本框 每次更改时都会调用一个函数 我想做的只是当用户停止输入 x 毫秒时才调用该函数 我知道如何使用 keyup 事件在 JQuery 中执行此操作 并且可能可以使其以这种方式
  • 使用 VSCode 创建并运行 Dart 控制台应用程序?

    我可以使用 VSCode 创建 Flutter 新应用程序 现在我想学习Dart编程语言 如何使用 VS Code 创建并运行 Dart 控制台应用程序 有一种简单的方法可以创建和运行 Dart 控制台应用程序 打开 VSCode 在 Ma
  • 将 Pandas DataFrame 写入换行符分隔的 JSON

    我首先通过 pandas read csv 函数将 CSV 读入 Pandas 数据帧 现在数据位于实际的数据框中 我尝试编写如下内容 for row in df iterrows row 1 to json path to file 这是
  • 在 MATLAB 中添加包围向量中 1 的其他值的附加值

    给定 MATLAB 中的零和一向量 其中零代表时间事件 我想在现有向量之前和之后添加额外的向量 以捕获额外的变化 Example 我想转 0 0 1 0 0 into 0 1 1 1 0 where 1 是新添加的 假设A为输入列向量 Fi
  • 根据位置重新排序行 SQL Server

    我在 SO 上看到了很多关于这个问题的问题 但没有一个与我的场景相关 除了基本的 CRUD 操作之外 我还算不上一个 SQL 专家 因此我对此很坚持 我有一张桌子 myTable rID newsID OrderPosition where
  • 在 Spark 中保存有序数据帧

    我正在尝试将有序数据帧保存到 HDFS 中 我的代码如下所示 dataFrame orderBy index write mode SaveMode Overwrite parquet getPath 我在两个不同的集群上运行相同的代码 一
  • 如何在 PHPUnit 测试中显示底层测试方法?

    我有测试套件 里面有很多测试 这是一个中等大小的 ok 4 CommodityBasketTest testStartsOutEmpty ok 5 CommodityBasketTest testCanAddACommodity ok 6