创建具有依赖项的具体类的 Moq [英] Create a Moq of a concrete class with dependencies

查看:51
本文介绍了创建具有依赖项的具体类的 Moq的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个具体的类 CalculatorService,我想测试其中的 CalculateBuyOrder() 方法.CalculatorService 有几个通过构造函数参数注入的依赖项,并且 CalculateBuyOrder() 在同一服务上调用另一个方法.

I have a concrete class CalculatorService of which I want to test CalculateBuyOrder() method. CalculatorService has several dependencies injected through constructor parameters and CalculateBuyOrder() calls another method on the same service.

我需要一个类的模拟

  1. 无需无参数构造函数即可创建(即自动模拟依赖树).
  2. 默认情况下已模拟(存根)所有方法,可选择覆盖和调用一个(或多个)方法的实际实现.

这似乎是一个如此明显和基本的用例,但我似乎既无法自己弄清楚也无法找到解释它的文档.我得到的最远的是使用 AutoMocker 来实现 1.,但 2. 让我很难过.

It seems such an obvious and basic use case, but I can't seem to neither figure it out myself nor find the documentation that explains it. The furthest I've gotten is using AutoMocker for achieving 1., but 2. has me stumped.

public class CalculatorService
    : ICalculatorService
{
    private readonly IMainDbContext _db;
    private readonly TradeConfig _tradeConfig;
    private readonly MainConfig _config;
    private readonly StateConfig _state;
    private readonly ICurrencyService _currencyService;
    private readonly IExchangeClientService _client;


    // Parameters need to be mocked
    public CalculatorService(MainDbContext db, TradeConfig tradeConfig, MainConfig config, StateConfig state, ICurrencyService currencyService, IExchangeClientService client)
    {
        this._db = db;
        this._tradeConfig = tradeConfig;
        this._config = config;
        this._state = state;
        this._currencyService = currencyService;
        this._client = client;
    }

    // This needs to be tested
    public async Task<OrderDto> CalculateBuyOrder(
        String coin,
        CoinPriceDto currentPrice,
        Decimal owned,
        IDictionary<TradeDirection, OrderDto> lastOrders,
        OrderDto existingOrder = null,
        TradeConfig.TradeCurrencyConfig tradingTarget = null,
        Decimal? invested = null)
    {

        // ...
        this.GetInvested();
        // ...
    }

    // This needs to be mocked
    public virtual IDictionary<String, Decimal> GetInvested()
    {
        // ...
    }
}

}

推荐答案

正如一些评论所说,您应该将接口放在构造函数中,例如伪代码:

As some of the comments have said you should place interfaces in your constructor as for an example pseudo code:

public class Foo : IFoo
{
    IBoo boo;
    IGoo goo;
    public Foo(IBoo boo, IGoo goo)
    {
        this.boo = boo;
        this.goo = goo;
    }
    public int MethodToTest(int num1,int num2)
    {
        //some code
        /*..*/ = boo.Method(num1,num2);
        //more code and return
    }
}

注意构造函数中的所有参数都是接口.然后你的测试方法看起来有点像这样

notice all the parameters in the constructor are interfaces. and then your test method would look a little like this

[TestMethod]
public void TestMethod()
{
    //setting up test
    var boo = new Mock<IBoo>();
    var goo = new Mock<IGoo>();
    var foo = new Foo(boo.object,goo.object);
    boo.Setup(x=>x.Method(1,2)).Returns(10);
    //running test
    var result = foo.MethodToTest(1,2);
    //verify the test
    Assert.AreEqual(12,result);
}

有关更多信息,请转到此链接 Moq Github.

For more information just go to this link Moq Github.

现在是问题的第二部分,在同一个类中模拟一个方法.这违背了模拟的目的,因为模拟是伪造"依赖关系.因此,要么重构代码以便您可以正确地模拟它,要么确保它调用的任何方法都以一种能够提供您可以使用的可靠输出的方式进行模拟.

Now for the second part of your question, mocking a method within the same class. This defeats the purpose of mocking, as mocking is to "fake" dependencies. So either restructure the code so you can mock it properly, or make sure any methods it calls are mocked in a way they'll give a reliable output that you can use.

这篇关于创建具有依赖项的具体类的 Moq的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆