Unit testing 单元测试-边缘情况是否需要单独的测试方法?
当单元测试时,测试相同方法的边缘案例是否需要单独的测试方法。例如,测试传递给以下函数的空字符串:Unit testing 单元测试-边缘情况是否需要单独的测试方法?,unit-testing,language-agnostic,Unit Testing,Language Agnostic,当单元测试时,测试相同方法的边缘案例是否需要单独的测试方法。例如,测试传递给以下函数的空字符串: public function add($numbers) { $numbers = preg_replace('/\s/', '', $numbers); if ($numbers === "") { return 0; } } 我显然想抓住边缘案例,例如: "" " " "\t \n" "asd" 等 那么需要多少测试方法来证明这种方法有效呢 pub
public function add($numbers)
{
$numbers = preg_replace('/\s/', '', $numbers);
if ($numbers === "") {
return 0;
}
}
我显然想抓住边缘案例,例如:
""
" "
"\t \n"
"asd"
等
那么需要多少测试方法来证明这种方法有效呢
public function testAddEmptyString()
{
$stringCalculator = new StringCalculator();
$this->assertSame(0, $stringCalculator->add(""));
}
public function testAddEmptyStringWithSpaces()
{
$stringCalculator = new StringCalculator();
$this->assertSame(0, $stringCalculator->add(" "));
}
public function testAddEmptyStringWithCharacters()
{
$stringCalculator = new StringCalculator();
$this->assertSame(0, $stringCalculator->add("asd"));
}
在这个简单的例子中(一个实际的函数,即没有副作用,没有异常,基本上每个测试用例一行),测试类将包含大量用于任何非平凡事物的方法。我认为一个测试方法就可以了
如果您有更复杂的测试用例需要设置代码,那么每个测试用例都应该有自己的测试方法。在这个简单的用例中(一个实际的功能,即没有副作用,没有异常,基本上每个测试用例一行),我会说一个测试方法就可以了
如果您有更复杂的测试用例需要设置代码,那么每个测试用例都应该有自己的测试方法。这当然是一个意见问题,所以IMHO,测试方法应该始终测试单个场景 话虽如此,考虑到您应该像对待生产代码一样关注测试代码,您应该努力实现干净的设计——在本例中 每种语言都有自己的方法来实现这一点,但通常提取一个方法就可以了。就其本身而言,进行许多测试并无害处,只要它们是孤立的、意图明确的等等 例如,xUnit(C#)解决此问题的方式如下所示:
[Theory]
[InlineData("")]
[InlineData(" ")]
[InlineData("\t \n")]
[InlineData("asd")]
public void Add_NonNumber_ZeroReturned(string numbers)
{
var underTest = new UnderTest();
var result = underTest.Add(numbers);
Assert.Equal(0, result);
}
这当然是一个意见问题,所以IMHO,一个测试方法应该总是测试一个场景 话虽如此,考虑到您应该像对待生产代码一样关注测试代码,您应该努力实现干净的设计——在本例中 每种语言都有自己的方法来实现这一点,但通常提取一个方法就可以了。就其本身而言,进行许多测试并无害处,只要它们是孤立的、意图明确的等等 例如,xUnit(C#)解决此问题的方式如下所示:
[Theory]
[InlineData("")]
[InlineData(" ")]
[InlineData("\t \n")]
[InlineData("asd")]
public void Add_NonNumber_ZeroReturned(string numbers)
{
var underTest = new UnderTest();
var result = underTest.Add(numbers);
Assert.Equal(0, result);
}
你应该有很多单独的测试方法,不要担心它们有多少 尝试将多个测试硬塞进一个方法的坏处在于,当测试失败时,您不知道破坏的真实程度,因为测试的一部分失败会阻止测试的其余部分运行。 当您看到一个测试中断并去修复它时,结果可能会出现更多的失败 如果您组织测试,以便在单独的测试中处理不同的情况,那么您将一次看到所有的失败
如果所有边缘案例都是传递不同数据的实例,并且它们都以相同的方式被调用,那么您可能需要检查您的测试框架是否支持参数化测试 你应该有很多单独的测试方法,不要担心它们有多少 尝试将多个测试硬塞进一个方法的坏处在于,当测试失败时,您不知道破坏的真实程度,因为测试的一部分失败会阻止测试的其余部分运行。 当您看到一个测试中断并去修复它时,结果可能会出现更多的失败 如果您组织测试,以便在单独的测试中处理不同的情况,那么您将一次看到所有的失败
如果所有边缘案例都是传递不同数据的实例,并且它们都以相同的方式被调用,那么您可能需要检查您的测试框架是否支持参数化测试 您应该有一个与测试分离的所有这些边缘案例值的数组
String[] edgeCaseValues = {""," ","\t \n","asd"};
然后,在测试中,您可以简单地通过它们进行循环,并将它们传递到您的函数中
foreach(var edgeCaseValue in edgeCaseValues)
{
$stringCalculator = new StringCalculator();
$this->assertSame(0, $stringCalculator->add(edgeCaseValue));
}
这样,您就可以在其他测试中重用它们,如果您添加了一个新的边缘案例值,它们将全部添加到所有测试中您应该拥有一个与测试分离的所有这些边缘案例值的数组
String[] edgeCaseValues = {""," ","\t \n","asd"};
然后,在测试中,您可以简单地通过它们进行循环,并将它们传递到您的函数中
foreach(var edgeCaseValue in edgeCaseValues)
{
$stringCalculator = new StringCalculator();
$this->assertSame(0, $stringCalculator->add(edgeCaseValue));
}
这样,您就可以在其他测试中重用它们,如果您添加新的边缘案例值,它们将全部添加到所有测试中