2017-03-08 53 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) 
}