繁体   English   中英

Moq在测试方法内部创建的对象

[英]Moq an object created inside the method being tested

在下面的示例中,我想测试TestMe.DoSomething()函数。

我想模拟此方法中使用的ISomething接口,并使其返回不同的值(取决于特定的单元测试。)

在现实生活中, ISomething接口逐渐呼唤昂贵的第三者资源-我绝对不想仅仅调用一个真正的ISomething

这是示例结构:

class TestMe
{
    public void DoSomething()
    {
        ISomething s = SomethingFactory();
        int i = s.Run();

        //do things with i that I want to test
    }

    private ISomething SomethingFactory()
    {
        return new Something();
    }
}

interface ISomething
{
    int Run();
}

class Something : ISomething
{
    public int Run()
    {
        return 1;
    }
}

这是无效的代码:

        var fakeSomething = new Mock<ISomething>();
        var testMe = new TestMe();
        Mock.Get(testMe).Setup(p => p.SomethingFactory()).Returns(fakeSomething.Object);
        testMe.DoSomething();

因为SomethingFactory()private ,所以我无法将该方法的返回值设置为所需的值。

关于如何解决这个问题有什么建议吗?

使工厂成为完整的接口/类,并从TestMe中删除SomethingFactory方法。

public interface ISomethingFactory {
  ISomething MakeSomething();
}

public sealed class SomethingFactory {
  public ISomething MakeSomething() {
    return new Something();
  }
}

class TestMe
{
    private readonly ISomethingFactory _somethingFactory;

    public TestMe(ISomethingFactory somethingFactory) {
      _somethingFactory = somethingFactory;
    }

    public void DoSomething()
    {
        ISomething s = _somethingFactory.MakeSomething();
        int i = s.Run();

        //do things with i that I want to test
    }
}

这将允许您模拟ISomethingFactory以返回ISomething的模拟。

尽管我认为您可能会反对这种解决方案,因为它太过激进了,但我认为它比制作一个没有被成员密封的课程要好得多,后者的唯一原因是要进行虚拟测试。

  1. 您可以注入依赖项。 如果您不想破坏所有调用者,则可以添加两个构造函数,并使用一个可以在测试中注入伪造的构造函数

     class TestMe { private readonly ISomething something; TestMe() : this(new RealSomething() { } TestMe(ISomething sth) { something = sth; } public void DoSomething() { ISomething s = SomethingFactory(); int i = s.Run(); //do things with i that I want to test } private ISomething SomethingFactory() { return new Something(); } } 
  2. 第二种方法是更改

     SomethingFactory 

    保护虚拟并在派生类中重写它并使用该类替代方法或进行设置的方法

     class TestableTestMe : TestMe { private readonly ISomething something; TestableTestMe(ISomething testSpecific) { something = testSpecific; } public void DoSomething() { ISomething s = SomethingFactory(); int i = s.Run(); //do things with i that I want to test } protected override ISomething SomethingFactory() { return something; } } 

此技术称为“提取并覆盖”

将SomethingFactory()更改为虚拟受保护,则可以使用Moq.Protected通过其名称访问该方法:

public class TestMe 
{
    public void DoSomething()
    {
        ISomething s = SomethingFactory();
        int i = s.Run();

        //do things with i that I want to test
    }

    protected virtual ISomething SomethingFactory()
    {
        return new Something();
    }
}

public interface ISomething
{
    int Run();
}

public class Something : ISomething
{
    public int Run()
    {
        return 1;
    }
}

因此,您可以运行以下测试:

        var fakeSomething = new Mock<ISomething>();
        fakeSomething.Setup(p => p.Run()).Returns(2);
        var testMe = new Mock<TestMe>();
        testMe.Protected().Setup<ISomething>("SomethingFactory").Returns(fakeSomething.Object);
        testMe.Object.DoSomething();

暂无
暂无

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

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