简体   繁体   English

在C#中的单元测试中模拟实现类和测试类

[英]Mocking an implementation class with test class within unit test in C#

I'm trying to write a simple unit test where I have wrapped the HttpContext.Current.Server.MapPath with an interface and implementation. 我正在尝试编写一个简单的单元测试,其中已使用接口和实现包装了HttpContext.Current.Server.MapPath。 I'm not positive if the implementation is in the right place. 如果实施在正确的位置,我不是很肯定。

public class FooGenerator
{
    ServerPathProvider serverPathProvider = new ServerPathProvider();

    public string generateFoo()
    {
        BarWebService bws = new BarWebService(serverPathProvider.MapPath("~/path/file"));
        return stuff;
    }
}


public class ServerPathProvider : IPathProvider
{
    public string MapPath(string path)
    {
        return HttpContext.Current.Server.MapPath(path);
    }
}

In the test I have my own implementation I want to use, but I cannot figure out how to inject this into the real class during the unit test. 在测试中,我有自己的实现,但是我无法弄清楚如何在单元测试中将其注入到真实的类中。

[TestClass()]
public class FooGeneratorTests
{
    [TestMethod()]
    public void generateFooTest()
    {
        FooGenerator fg = new FooGenerator();

        //Some kind of mock dependency injection
        Mock<IPathProvider> provider = new Mock<IPathProvider>();
        //stub ServerPathProvider object with provider mock

        string token = fg.generateFoo;
        Assert.IsNotNull(token);
    }
}

public class TestPathProvider : IPathProvider
{
    public string MapPath(string path)
    {
        return Path.Combine(@"C:\project\", path);
    }
}

Finally, here is my interface just in case. 最后,这是我的界面,以防万一。 Basically I just want to swap out two implementations depending on whether or not I am unit test. 基本上,我只想交换两种实现,具体取决于我是否进行单元测试。 This is my first unit test so much of this is new to me. 这是我的第一个单元测试,所以对我来说很多都是新的。 Sorry if I'm missing something basic, but I've been digging through stack overflow for a while now and can't find the steps to do this part. 抱歉,如果我缺少一些基本的知识,但是我已经研究了一段时间的堆栈溢出问题,并且找不到执行此部分的步骤。

public interface IPathProvider
{
    string MapPath(string path);
}

There are a few options. 有一些选择。

Accepting parameters 接受参数

In general, you want your FooProvider to have a IPathProvider instead of ServicePathProvider as its servicePathProvider member variable. 通常,您希望FooProvider拥有一个IPathProvider而不是ServicePathProvider作为其servicePathProvider成员变量。

You can have two constructors for FooProvider : 您可以为FooProvider提供两个构造FooProvider

  1. A default constructor that instantiates servicePathProvider = new ServicePathProvider(); 实例化servicePathProvider = new ServicePathProvider();默认构造函数servicePathProvider = new ServicePathProvider(); , and
  2. A non-default constructor that instantiates takes in a IServiceProvider as an argument and sets servicePathProvider to that. 实例化的非默认构造函数接受IServiceProvider作为参数,并将servicePathProvider设置为该参数。

Generic classes 通用类

Change FooProvider as follows: 如下更改FooProvider

public class FooProvider<T> where T : IServiceProvider, new()

In non-unit testing code, you would use FooProvider<ServicePathProvider> and for unit tests, you would use FooProvider<Mock> . 在非单元测试代码中,您将使用FooProvider<ServicePathProvider> ;对于单元测试,您将使用FooProvider<Mock>

This makes FooProvider accepts a generic type T which is a subtype of IServiceProvider and has a default constructor (that's the new() part) in the where clause. 这使得FooProvider接受通用类型T ,它是IServiceProvider的子类型, 并且在where子句中具有默认构造函数(即new()部分)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM