对于那些不确定“受限制的非决定论”的含义的人,我推荐Mark Seeman的post。
该想法的本质是测试仅具有影响SUT行为的数据的确定性值。不“相关”的数据在某种程度上可以是“随机的”。
我喜欢这种方法。抽象的数据越多,预期就会变得越清晰和富有表现力,实际上,无意识地将数据纳入测试变得更加困难。
我正试图将这种方法(以及AutoFixture)“推销”给我的同事,昨天我们就此进行了长时间的讨论。
他们提出了一个有趣的论点,即由于随机数据而不能稳定地进行调试
起初看起来有点奇怪,因为我们都同意影响数据的流量不能是随机的,这种行为是不可能的。尽管如此,我还是休息一下,彻底思考这个问题。
我终于遇到了以下问题:
但我的一些假设首先是:
考虑同一测试的这两个变体:
[TestMethod]
public void DoSomethig_RetunrsValueIncreasedByTen()
{
// Arrange
ver input = 1;
ver expectedOutput = input+10;
var sut = new MyClass();
// Act
var actualOuptut = sut.DoeSomething(input);
// Assert
Assert.AreEqual(expectedOutput,actualOutput,"Unexpected return value.");
}
/// Here nothing is changed besides input now is random.
[TestMethod]
public void DoSomethig_RetunrsValueIncreasedByTen()
{
// Arrange
var fixture = new Fixture();
ver input = fixture.Create<int>();
ver expectedOutput = input+10;
var sut = new MyClass();
// Act
var actualOuptut = sut.DoeSomething(input);
// Assert
Assert.AreEqual(expectedOutput,actualOutput,"Unexpected return value.");
}
到目前为止,上帝,一切正常,生活是美好的,然后需求发生变化,DoSomething
改变了它的行为:现在只有当它低于10时才增加输入,否则增加10。
这里发生了什么?使用硬编码数据的测试通过(实际上是意外),而第二次测试有时会失败。而且他们都是错误的欺骗测试:他们检查不存在的行为。
无论数据是硬编码还是随机数据都无关紧要:它只是无关紧要。然而,我们没有强有力的方法来检测这种“死”的测试。
所以问题是:
有没有好的建议如何以这种情况出现的方式编写测试?
答案 0 :(得分:6)
答案实际上隐藏在这句话中:
[..]然后需求变更,DoSomething改变其行为[..]
如果你这样做会不会更容易:
expectedOutput
,以满足新要求。DoSomething
- 让测试再次通过。此方法与AutoFixture等特定工具无关,它只是测试驱动开发。
AutoFixture在哪里真的有用吗?使用AutoFixture,您可以最小化测试的编配部分。
这是原始测试,使用AutoFixture.Xunit
以惯用方式编写[Theory, InlineAutoData]
public void DoSomethingWhenInputIsLowerThan10ReturnsCorrectResult(
MyClass sut,
[Range(int.MinValue, 9)]int input)
{
Assert.True(input < 10);
var expected = input + 1;
var actual = sut.DoSomething(input);
Assert.Equal(expected, actual);
}
[Theory, InlineAutoData]
public void DoSomethingWhenInputIsEqualsOrGreaterThan10ReturnsCorrectResult(
MyClass sut,
[Range(10, int.MaxValue)]int input)
{
Assert.True(input >= 10);
var expected = input * 10;
var actual = sut.DoSomething(input);
Assert.Equal(expected, actual);
}
此外,除xUnit.net外,还有support for NUnit 2。
HTH
答案 1 :(得分:5)
&#34;然后需求发生变化,DoSomething改变其行为&#34;
是吗,真的吗?如果DoSomething
更改了行为,则会违反Open/Closed Principle(OCP)。您可能决定不关心这一点,但它与why we trust tests密切相关。
每次更改现有测试时,都会降低其可信度。每次更改现有生产行为时,您都需要审核所有触及该生产代码的测试。理想情况下,您需要访问每个此类测试,并简要地更改实现,以确定如果实现错误,它仍然会失败。
对于微小的变化,这可能仍然是实用的,但即使是适度的变化,也要明智地遵守OCP:不要改变现有的行为; 并排添加新行为,让旧行为萎缩。
在上面的例子中,可能很清楚AutoFixture测试可能是非确定性的错误,但从更概念的角度来看,如果你在不审查测试的情况下改变生产行为,那么完全有可能可能会默默地变成false negatives。这是与单元测试相关的一般问题,并非特定于AutoFixture。