C# 测试接口(TDD)的多种实现

C# 测试接口(TDD)的多种实现,c#,tdd,nunit,C#,Tdd,Nunit,在创建多个接口实现以确保符合接口契约时,最佳实践是什么 public interface IFoo { /// <exception cref="System.ArgumentNullException"> /// If <paramref name="baz"> is <c>null</c>. /// </exception> void Bar(Baz baz); } 这是一种有效的TDD方法吗 测试

在创建多个接口实现以确保符合接口契约时,最佳实践是什么

public interface IFoo {
    /// <exception cref="System.ArgumentNullException">
    /// If <paramref name="baz"> is <c>null</c>.
    /// </exception>
    void Bar(Baz baz);
}
这是一种有效的TDD方法吗

  • 测试最初不会编译,因为
    SpecialFoo
    类尚未定义

  • 创建最小的
    SpecialFoo
    实现,该实现可编译但无法通过所有测试

  • 测试将编译,但不会通过,因为最小的
    SpecialFoo
    类将无法满足接口的期望


  • 或者我应该为
    IFoo
    的每个新实现逐个重新实现每个测试吗?

    这是一种非常有效的方法,可以确保当前(和未来)实现者遵守接口的(语义)契约。我第一次听说这类测试是J.B.Rainsberger,他打电话给他们

    如果您主要依赖于独立测试(即大量使用模拟),那么契约测试是编写集成测试(将多个真实对象粘合在一起)的必要替代方法。隔离单元测试验证单元是否在隔离状态下正确工作,契约测试验证您对协作者所做的所有假设是否都由其实现保证。有关这种独立测试风格的更多信息,您可以在J.B的博客上阅读更多。一个开始的好地方是

    J.B.是我认识的最铁杆的TDD'ers之一。他使用了一种TDD风格,专注于从外到内的TDD,只处理独立的单元测试(即大量使用模拟)。在他的方法中,您测试驱动一个SUT,并为每个协作者创建接口,您在针对SUT的独立单元测试中模拟这些接口。在设计SUT时,您可以更深入地测试协作者的实现。为了确保这些对象在粘合在一起时能够协同工作,他还建议编写这些契约测试,作为编写将实际对象连接在一起的集成测试的替代方案:对象对协作者的每个假设(例如:“实现此接口的所有对象如果找不到具有此id的人,则返回null”)可以在契约测试中具体化

    public abstract class IFooTestsBase {
        protected IFoo Foo;
    
        [Test]
        [ExpectedException(typeof(ArgumentNullException))]
        public void Bar_ThrowsException_WhenBazArgumentIsNull() {
            Foo.Bar(null);
        }
    }
    
    [TestFixture]
    public class SpecialFooTests : IFooTestsBase {
        [TestFixtureSetUp]
        public void Init() {
            // Provide instance of `SpecialFoo` for inherited tests.
            Foo = new SpecialFoo();
        }
    
        // TDD as normal from here...
    }