Modus Operandi
Modus Operandi

Reputation: 641

Create a Moq of a concrete class with dependencies

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.

I need a mock of the class that

  1. Can be created without parameterless constructor (i.e., automatically mocking the dependency tree).
  2. Has all methods mocked (stubbed) by default, with the option of overriding and calling the real implementation on one (or several) methods.

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()
    {
        // ...
    }
}

}

Upvotes: 0

Views: 1929

Answers (1)

Dennis.Verweij
Dennis.Verweij

Reputation: 136

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);
}

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.

Upvotes: 1

Related Questions