2014-03-04 60 views
5

使用xUnit.net什么是干净的(可读/可理解的可维护)的方式来重复使用相同的测试用于同一接口的多个实现?重复使用相同的测试用于不同的实现

我测试的行为断言部分都是一样的(因为接口的所有实现都应该有同样的表现)。只是SUT对于每次测试运行都是不同的,对于某些特定测试排列部分略有不同。

例如,我有以下接口的多个实现(MemoryRepository,FileReposity ...)。

interface IRepository 
{ 
    object GetById(string id); 
    void Set(string id, object value); 
} 

现在我的测试中都应该保证所有实现相同的行为:

// all implementations of IRepository must behave like this 
// so do this test for all implementations 
[Fact] 
public void GetRetrievesWhatWasPut() 
{ 
    IRepository sut = new MemoryRepository(); 
    sut.Set("key", 10); 
    var result = sut.Get("key"); 
    result.Should().Be(10); 
} 

回答

6

你可以考虑写test classes as generic classes

public abstract class IntervalFacts<T> 
{ 
    [Theory, AutoCatalogData] 
    public void MinimumIsCorrect(IComparable<T> first, 
     IComparable<T> second) 
    { 
     var sut = new Interval<T>(first, second); 
     IComparable<T> result = sut.Minimum; 
     Assert.Equal(result, first); 
    } 
} 

public class DecimalIntervalFacts : IntervalFacts<decimal> { } 
public class StringIntervalFacts : IntervalFacts<string> { } 
public class DateTimeIntervalFacts : IntervalFacts<DateTime> { } 
public class TimSpanIntervalFacts : IntervalFacts<TimeSpan> { } 

这个特殊的例子采用的AutoFixture的优势组合具体类的能力,这为您省去了实例化每个具体实例的麻烦。

改变安排阶段比较困难,但根据你需要做的事情,再次,你可以引入一些约定到AutoFixture,以便它自动地根据类型改变创建的实例。


对于在OP类型,你可以写测试是这样的:

public abstract class RepositoryFacts<T> where T : IRepository 
{ 
    [Theory, AutoRepositoryData] 
    public void GetRetrievesWhatWasPut(T sut) 
    { 
     sut.Set("key", 10); 
     var result = sut.Get("key"); 
     result.Should().Be(10); 
    }   
} 

public class MemoryRepositoryFacts : RepositoryFacts<MemoryRepository> { } 
public class FileReposityRepositoryFacts : RepositoryFacts<FileReposity> { } 
+0

我不太了解如何使用通用的测试类,帮助我改变SUT。你的例子不会改变SUT。 – bitbonk

+0

但它可以;请求'T'而不是'IComparable '... –

+0

我认为可能存在某种误解,我用一个例子更新了我的问题。我看到我可以如何使用'[Theory]'和'DataAttribute'来数据驱动SUT,但我没有看到使用泛型的好处。 – bitbonk

相关问题