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

编程入门 行业动态 更新时间:2024-10-26 13:19:36
许多测试用例涵盖了一个函数 - phpunit(Many test cases to cover a function - phpunit)

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

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

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

最满意答案

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

每个测试应测试一个且只测试一件事 每项测试都应尽可能愚蠢

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

存在第二个特征是因为每次测试失败,都必定存在问题。 问题只能存在于两个地方之一(忽略PHP及其扩展中的错误,或单元测试程序中):在测试代码中,或在测试本身中。 “聪明”的测试会让你很难确定它是哪种情况,并且你不想花一两个小时追捕你班上的一个bug,因为事实证明它实际上是一个错误的测试。

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

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

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

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

黑盒测试的一个好处是,如果你知道规格,你可以在任何代码甚至测试之前编写测试。 然后,您可以开始实现代码,对其进行测试,针对失败的测试进行更正并重复此过程,直到获得100%的通过率。 这称为测试驱动开发。

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. "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. 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.

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. 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. This is called Test Driven Development.

更多推荐

本文发布于:2023-07-18 04:42:00,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1154942.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:一个函数   测试

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!