简体   繁体   English

许多测试用例涵盖了一个函数 - phpunit

[英]Many test cases to cover a function - phpunit

For the following function I need to write more test cases, I have already written one, can someone give some ideas, Perhaps to test return values of intermediate function calls. 对于以下函数,我需要编写更多的测试用例,我已经编写了一个,可以有人给出一些想法,也许是为了测试中间函数调用的返回值。

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

I have written following case already, 我已经写了以下案例,

 /**
 * 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)
    );
}

As a general rule, unit tests should exhibit two traits: 作为一般规则,单元测试应该表现出两个特征:

  • Each test should test one and only one thing 每个测试都应测试一个且只测试一件事
  • Each test should be as dumb as humanly possible 每项测试都应尽可能愚蠢

The reason for the first trait is that if a test fails it will log which test case method triggered the failure. 第一个特征的原因是如果测试失败,它将记录哪个测试用例方法触发了失败。 If that method tests lots of things it makes it more of a nuisance to determine the exact failure. 如果该方法测试了很多东西,那么确定确切的失败就更加麻烦了。

The second trait exists because every time a test fails, then there must be a problem. 存在第二个特征是因为每次测试失败,都必定存在问题。 The problem can only exist in one of two places (ignoring bugs in PHP and its extensions, or in the unit tester): in the code under test, or in the test itself. 问题只能存在于两个地方之一(忽略PHP及其扩展中的错误,或单元测试程序中):在测试代码中,或在测试本身中。 "Clever" tests will make it difficult to determine which case it is, and you don't want to spend an hour or two hunting down a bug in your class when it turns out it's actually the test that's buggy. “聪明”的测试将很难确定它是哪种情况,并且你不想花一两个小时追捕你班上的一个错误,而事实证明它实际上是测试的错误。

In your example above your current test is pretty good, but it breaks the first rule (there's two tests happening at once). 在上面的示例中,您当前的测试非常好,但它打破了第一条规则(一次发生了两次测试)。 Unless running the method under test is really expensive it might be worth having this test case twice, with the first run asserting the expected shortest path and the second one asserting the expected cost (and if your method does have an expensive run time then there's an incentive to try and optimise it right there :) ). 除非运行测试中的方法非常昂贵,否则可能值得将此测试用例两次,第一次运行断言预期的最短路径,第二次断言预期成本(如果您的方法确实有一个昂贵的运行时间,那么有一个激励尝试并优化它在那里:))。

Your test may also break the second rule because I have no idea what $this -> graph is or how it's set up. 你的测试也可能会破坏第二条规则,因为我不知道$ this - > graph是什么或它是如何设置的。 Is this an actual business object or just a mockup of it? 这是一个实际的业务对象还是仅仅是一个模型? You might want to look into the mocking an stubbing capabilities of PHPUnit. 您可能希望研究模拟PHPUnit的存根功能。

Regarding test strategies, there are two general approaches - Black box testing (where you test a unit against its specifications but treat it like you have no knowledge of its internal workings) and glass box (where you use your knowledge of the unit's internal workings to devise tests). 关于测试策略,有两种常规方法 - 黑盒测试(根据其规格测试单元,但对待它就像你不了解其内部工作原理)和玻璃盒(在那里你使用你对单元内部工作的了解)设计测试)。 My preferred approach it to mainly adopt a black box strategy, build tests around the specs, and then once I've got the spec fully covered move to a glass box strategy to write additional tests that will cover any code paths that the black box test doesn't exercise. 我首选的方法是主要采用黑盒策略,围绕规范构建测试,然后一旦我完全覆盖规范,就转向玻璃盒策略,编写额外的测试,覆盖黑盒测试的任何代码路径不运动。

Testing is often about boundaries, as in testing responses to input when that input is both valid and invalid. 测试通常与边界有关,如在输入有效且无效时测试对输入的响应。 So for each method your class has, you want one typical case (what's often called the "happy path") that demonstrates typical usage, a number of extreme but still valid inputs, a range of inputs that are just outside the valid range (if your method excepts numbers in the range 1-10 then a test case with 0 and a test case with 11 would cover those cases) and a test case with data wildly outside of the valid range. 因此,对于您的课程所具有的每种方法,您需要一个典型的案例(通常称为“快乐路径”)来演示典型用法,一些极端但仍然有效的输入,一系列输入超出有效范围(如果你的方法除了1-10范围内的数字,然后是0的测试用例和11的测试用例将覆盖这些情况)和一个测试用例,其数据大大超出有效范围。 Many errors in programming occur at the transition between valid and invalid input (the off-by-one error is probably the most notorious example) so your tests should cover those regions thoroughly. 编程中的许多错误发生在有效输入和无效输入之间的转换(逐个错误可能是最臭名昭着的例子),因此您的测试应该彻底覆盖这些区域。

One nice thing about black box testing is that if you know the specs, you can write the tests before there's any code to even test. 黑盒测试的一个好处是,如果你知道规格,你可以在任何代码甚至测试之前编写测试。 Then you can start implementing code, test it, correct it for failed tests and repeat this process until you get a 100% pass rate. 然后,您可以开始实现代码,对其进行测试,针对失败的测试进行更正并重复此过程,直到获得100%的通过率。 This is called Test Driven Development. 这称为测试驱动开发。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM