2017-03-08 67 views
1

我想嘲笑一個具體的類,具體SortedDictionary。C#模擬具體類。怎麼樣?

上下文:

我有定義爲低於LocationMapper類:

public class LocationMapper 
{ 
    private SortedDictionary<string, Location>() locationMap; 
    public LocationMapper() 
    { 
    this.locationMap = new SortedDictionary<string, Location>(); 
    } 

    public LocationMapper(SortedDictionary<string, Location> locations) 
    { 
    this.locationMap = locations; 
    } 

    public Location AddLocation(Location location) 
    { 
    if(! locationMap.ContainsKey(location.Name)) 
    { 
     locationMap.Add(location.Name, location) 
    } 
    return locationMap[location.Name]; 
    } 
} 

單元測試AddLocation(),我需要模擬具體類SortedDictionary <>。不幸的是,NSubstitute不允許它。

The unit test that I had envisioned to write is below 
[Test] 
public void AddLocation_ShouldNotAddLocationAgainWhenAlreadyPresent() 
{ 
    var mockLocationMap = ;//TODO 
    //Stub mockLocationMap.ContainsKey(Any<String>) to return "true" 
    locationMapper = new LocationMapper(mockLocationMap); 
    locationMapper.AddLocation(new Location("a")); 
    //Verify that mockLocationMap.Add(..) is not called 
} 

你怎麼會去用這種方式在DOTNET的編寫單元測試?或者你不採取這種已知約束的路徑?

您的幫助是非常感謝。

+3

爲什麼嘲笑呢?爲什麼不創建一個實例並將其傳入?你有完全的控制來填補它,但是你想,所以我認爲你可以斷言結果。如果它是一個接口,那麼肯定是模擬的,但用一個具體的字典,我不認爲它是需要的。 – TyCobb

+0

你究竟在測試什麼?在我看來,你實際上正在測試SortedDictionary做它保證做的事情。你希望達到什麼價值? –

+0

@TyCobb,我已經用我的單元測試偏好/偏好作爲模板單元測試用例更新了這個問題,供您細讀。 – karthiks

回答

2

另一種方法是使用單元測試工具,它允許你嘲笑具體類,比如我使用Typemock隔離,並用它能夠創建你想使測試:

[TestMethod] 
public void TestMethod1() 
{ 
    var fakeLocationMap = Isolate.Fake.Instance<SortedDictionary<string, Location>>(); 

    Isolate.WhenCalled(() => fakeLocationMap.ContainsKey(string.Empty)).WillReturn(true); 

    var instance = new LocationMapper(fakeLocationMap); 
    var res = instance.AddLocation(new Location("a")); 

    Isolate.Verify.WasNotCalled(() => fakeLocationMap.Add(string.Empty, null)); 
} 
3

你不應該在這裏嘲笑字典。實際上它是LocationMapper類的實現細節。它應該通過封裝來隱藏。您可以使用其他任何方式來存儲位置 - 數組,列表或簡單字典。 LocationMapper是否符合要求並不重要。這種情況下的要求是什麼?像

位置映射器的東西應該能夠映射將其加入到映射器

位置目前您的映射是相當無用的,並將其添加沒什麼字典行爲。你缺少核心 - 映射。我只能假設這個班將如何使用。您需要一些公共接口進行映射。而測試應該像(這裏使用AutoFixture和FluentAssertions):

var mapper = new LocationMapper(); 
var location = fixture.Create<Location>(); 
mapper.AddLocation(location); 
mapper.Map(location.Name).Should().Be(location); 

雖然本次測試合格,您可以添加地點映射,與使用映射器映射的位置。

+0

我添加了上下文的代碼,正如我在文章中提到的那樣。這不是完整的: - / – karthiks

0

您有兩種選擇:如果您使用VS Enterprise,請使用Microsoft Fakes爲您的課程生成Shim。 (ping通我,如果你想有一個樣品)>

如果你不使用VS企業(如大多數人在這裏),你將不得不訴諸反思:

[Test] 
public void AddLocation_ShouldNotAddLocationAgainWhenAlreadyPresent() 
{ 
    var locationMapper = new LocationMapper(mockLocationMap); 
    locationMapper.AddLocation(new Location("a")); 
    var dict = ((SortedDictionary<string, Location>)typeof(LocationMapper).GetField("locationMap", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(locationMapper)); 
    Assert.AreEqual("a", dict.FirstOrDefault().Name) 
}