2014-03-04 62 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

相關問題