【问题标题】:Many test cases to cover a function - phpunit许多测试用例涵盖一个功能 - phpunit
【发布时间】:2015-05-06 12:28:51
【问题描述】:

对于下面的函数我需要写更多的测试用例,我已经写了一个,谁能给一些想法,也许是为了测试中间函数调用的返回值。

 public function calculateShortestPath($graphObj, $start, $destination)
{
    $shortestPath = null;

    if ($this->validateParams($graphObj, $start, $destination) == true) {

        $result = $this->getAllVerticesAndNeighbours($graphObj);

        $vertices = $result[self::VERTICES];
        $neighbours = $result[self::NEIGHBOURS];

        $vertexCost = array_fill_keys($vertices, self::INFINITY);
        $visitedVertices = array_fill_keys($vertices, null);

        $vertexCost[$start] = 0;
        $vertexQueue = $vertices;

        $result = $this->getShortestPath($vertexQueue, $vertexCost, $neighbours, $visitedVertices, $destination);

        $vertexCost = $result[self::VERTEX_COST];
        $shortestPathVertices = $result[self::SHORTEST_PATH_VERTICES];

        $path = $this->getRefinedShortestPath($shortestPathVertices, $destination);

        $shortestPath = new ShortestPath($path, $vertexCost[$destination]);

    }

    return $shortestPath;
}

我已经写过下面的案例了,

 /**
 * Test for calculateShortestPath function
 *
 * @param string|int $start starting point
 * @param string|int $destination destination point
 * @param array $expectedShortestPath expected shortest path
 * @param int|float $expectedCost expected cost
 * @dataProvider testCalculateShortestPathDataProvider
 */
public function testCalculateShortestPath($start, $destination, $expectedShortestPath, $expectedCost)
{
    $actualResult = $this->shortestPathCalc->calculateShortestPath($this->graph, $start, $destination);

    /* @var $actualResult ShortestPath */
    $this->assertEquals(
        $expectedShortestPath,
        $actualResult->getPath(),
        sprintf('Incorrect shortest path from %d to %d !', $start, $destination)
    );

    $this->assertEquals(
        $expectedCost,
        $actualResult->getCost(),
        sprintf('Incorrect shortest path cost from %d to %d !', $start, $destination)
    );
}

【问题讨论】:

  • 我需要写更多的测试用例 -- 为什么?
  • 只是为了确保函数不会在中间调用中中断,还有其他意见吗?我也为中间函数编写了单独的测试
  • 我不确定这种方法的作用和方式。所以我不能建议你如何测试你的 API。我只能提供常见的建议:尝试寻找边缘案例,探索覆盖范围。

标签: php unit-testing symfony phpunit


【解决方案1】:

作为一般规则,单元测试应该表现出两个特征:

  • 每个测试都应该只测试一件事
  • 每个测试都应该尽可能地愚蠢

第一个特征的原因是,如果测试失败,它将记录哪个测试用例方法触发了失败。如果该方法测试了很多东西,那么确定确切的故障就更麻烦了。

存在第二个特征是因为每次测试失败时,就一定有问题。问题只能存在于以下两个地方之一(忽略 PHP 及其扩展或单元测试器中的错误):被测代码或测试本身。 “聪明”的测试会让人很难确定它是哪种情况,而且你不想花一两个小时在你的课堂上寻找一个错误,而事实证明它实际上是有错误的测试。

在上面的示例中,您当前的测试非常好,但它违反了第一条规则(同时发生了两个测试)。除非运行被测方法真的很昂贵,否则可能值得两次使用这个测试用例,第一次运行断言预期的最短路径,第二次断言预期的成本(如果你的方法确实有一个昂贵的运行时间,那么有一个激励在那里尝试和优化它:))。

您的测试也可能违反第二条规则,因为我不知道 $this -> 图是什么或它是如何设置的。这是一个实际的业务对象还是只是它的模型?您可能想研究 PHPUnit 的模拟存根功能。

关于测试策略,有两种通用方法 - 黑盒测试(您根据其规格测试一个单元,但将其视为您不了解其内部工作原理)和玻璃盒测试(您使用您对单元的知识的了解)设计测试的内部工作)。我的首选方法是主要采用黑盒策略,围绕规范构建测试,然后一旦我完全涵盖了规范,就转向玻璃盒策略来编写额外的测试,这些测试将涵盖黑盒测试的任何代码路径不运动。

测试通常与边界有关,例如在输入有效和无效时测试对输入的响应。因此,对于您的班级拥有的每种方法,您都需要一个典型案例(通常称为“快乐路径”)来演示典型用法、一些极端但仍然有效的输入、刚好超出有效范围的输入范围(如果您的方法将 1-10 范围内的数字除外,然后一个 0 的测试用例和一个 11 的测试用例将涵盖这些情况)和一个数据大大超出有效范围的测试用例。编程中的许多错误发生在有效输入和无效输入之间的转换(一对一错误可能是最臭名昭著的例子),因此您的测试应该彻底覆盖这些区域。

关于黑盒测试的一个好处是,如果您了解规范,您可以在有任何代码进行测试之前编写测试。然后你可以开始实现代码,测试它,纠正失败的测试并重复这个过程,直到你获得 100% 的通过率。这称为测试驱动开发。

【讨论】:

    猜你喜欢
    • 2020-02-11
    • 1970-01-01
    • 2013-07-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-06-09
    相关资源
    最近更新 更多