Rob*_*nik 5 theory nunit unit-testing
假设我想将我的NUnit参数化测试方法改为理论.就理论而言,它们应该定义断言将通过的所有假设/先决条件.根据NUnit文档:
[将理论与参数化测试进行比较]另一方面,理论作出一般性陈述,即所有断言都将通过满足某些假设的所有论证.
但据我了解,这意味着被调用的PUT代码应基本上转化为假设.完全.
那么理论有什么意义呢?因为我们的算法会写两次.首先是可测试代码,其次是理论假设.因此,如果我们在算法中引入错误,我们的代码和测试可能会有相同的错误.那有什么意义呢?
假设我们有一个只支持数字的校验和方法,我们想用理论测试它.我们来写一个理论:
static Regex rx = new Regex(@"^\d+$", RegexOptions.Compiled);
[Theory]
public void ChecksumTheory(string value)
{
Assume.That(!string.IsNotNullOrWhiteSpace(value));
Assume.That(value.Length > 1); // one single number + checksum = same number twice
Assume.That(rx.IsMatch(value));
var cc = new ChecksumValidator();
bool result = cc.ValidateValue(value);
Assert.IsTrue(result); // not really as algorithm assumptions are missing
}
Run Code Online (Sandbox Code Playgroud)
这是一个非常好的理论,除了没有实际实现测试的代码算法并将其表达为一组假设,其断言仍然不会通过,因为没有明确的算法假设我们无法知道验证的结果是什么.
当我们只需要对输入状态提供假设,即检查特定值是否正确设置或它们的组合是否相关时,理论似乎相当简单和简洁:
[Theory]
public void Person_ValidateState(Person input)
{
Assume.That(input.Age < 110);
Assume.That(input.Birth < input.Death || input.Death == null);
...
}
Run Code Online (Sandbox Code Playgroud)
我还旨在在测试中引入假设,而不是使用参数化测试。但由于类似的想法,我仍然没有开始。
假设的目标是通过应用过滤器将给定输入描述为不可数(或者说庞大但完整)值集的子集。通过这个,你上面的代码是绝对正确的,但是在这种情况下,你必须编写几个类似的测试来进行负面结果测试 - 例如。当 的结果cc.ValidateValue(...)是时false。再次 - 为了便于理解 - 我仍然会依赖于精心挑选的参数来对这个简单函数进行参数化测试。
另一方面,假设对于测试更复杂的业务逻辑可能有用。想象一下,您有一个装满豪华汽车的车库,并且您想在一些偏远的地形上粉碎汽油 - 另外,让我们想象这是一个业务需求,因此您需要为其编写测试(这将是多么酷!)。然后你可以编写这样的测试:
[Theory]
public void CarCanDriveOnMuddyGround(Car car)
{
Assume.That(car.IsFourWheelDrive);
Assume.That(car.HasMotor);
Assume.That(car.MaxSpeed > 50);
Assume.That(car.Color != "white");
bool result = car.DriveWithGivenSpeedOn<MuddyGround>(50);
Assert.IsTrue(result);
}
Run Code Online (Sandbox Code Playgroud)
看看这与 BDD 方法有何密切关系?和你一样,我也不太相信使用简单单元测试的假设。但我确信根据不同的测试级别(单元、集成、系统、用户接受程度)使用不同的测试功能方法(参数化、断言)是个好主意。
再次考虑一下你的具体问题。现在我明白你的意思了。用我的话来说:您需要假设给定的值会给出积极的结果,然后才能断言它会给出积极的结果。正确的?我认为你找到了一个很好的例子来解释为什么理论并不总是有效。
无论如何,我尝试用一个稍微简单的示例来解决它(为了可读性)。但我承认这不太有说服力:
public class TheoryTests
{
[Datapoints]
public string[] InvalidValues = new[] { null, string.Empty };
[Datapoints]
public string[] PositiveValues = new[] { "good" };
[Datapoints]
public string[] NegativeValues = new[] { "Bad" };
private bool FunctionUnderTest(string value)
{
return value.ToLower().Equals(value);
}
[Theory]
public void PositiveTest(string value)
{
Assume.That(!string.IsNullOrEmpty(value));
var result = FunctionUnderTest(value);
Assert.True(result);
}
[Theory]
public void PassingPositiveTest(string value)
{
Assume.That(!string.IsNullOrEmpty(value));
Assume.That(!NegativeValues.Contains(value));
var result = FunctionUnderTest(value);
Assert.True(result);
}
}
Run Code Online (Sandbox Code Playgroud)
PositiveTest显然会失败,因为缺少算法假设。请参阅正文中的第二行,PassingPositiveTest它可以防止测试失败。当然,缺点是这实际上是基于示例的测试,而不是纯粹基于理论的测试。欢迎更好的想法。