Mocking with moq, trying to pass an object to constructor having multiple parameter

c#, moq, unit-testing

Solution

If `CodeService` is under test, then you want to be mocking its dependencies, not the `CodeService` itself.

You'll need to provide `Mock`s for all of the dependencies of `CodeService` to the constructor, i.e.:

     var currencycodes = new List<SomeCodes>
     {
        new CurrencyCodes(){Id = 1, Code = "IND", Description = "India"},
        new CurrencyCodes(){Id = 2, Code = "USA", Description = "UnitedStates"},
        new CurrencyCodes(){Id = 3, Code = "UAE", Description = "ArabEmirates"}
     };
     var mockEfContext = new Mock<EFDbContext>();
     var mockCacheManager = new Mock<ICacheManager>();
     var mockSessionManager = new Mock<ISessionManager>();
     var mockAppSettings = new Mock<IApplicationSettings>();

     // Setups for relevant methods of the above here, e.g. to test a cache miss
     mockEfContext.SetupGet(x => x.SomeCodes)
        .Returns(currencycodes); // Canned currencies
     mockCacheManager.Setup(x => x.Get<IEnumerable<SomeCodes>>(It.IsAny<string>()))
        .Returns<IEnumerable<SomeCodes>>(null); // Cache miss

     // Act
     var service = new CodeService(mockEfContext.Object, mockCacheManager.Object,
        mockSessionManager.Object, mockAppSettings.Object);
     var codes = service.GetAllCodes();

     // Assert + Verify
     mockCacheManager.Verify(x => x.Get<IEnumerable<SomeCodes>>(
        It.IsAny<string>()), Times.Once, "Must always check cache first");
     mockEfContext.VerifyGet(x => x.SomeCodes,
        Times.Once, "Because of the simulated cache miss, must go to the Db");
     Assert.AreEqual(currencycodes.Count, codes.Count(), "Must return the codes as-is");

Edit If you however mean that the next layer up of your code is under test, the principal is the same:

var mockCodeService = new Mock<ICodeService>();
mockCodeService.Setup(x => x.GetAllCodes())
    .Returns(currencycodes); // Now we don't care whether this is from cache or db 

var higherLevelClassUsingCodeService = new SomeClass(mockCodeService.Object);
higherLevelClassUsingCodeService.DoSomething();

mockCodeService.Verify(x => x.GetAllCodes(), Times.Once); // etc

Edit 2 I've fixed a couple of typos in the code, and assuming `CurrencyCodes` inherits `SomeCodes` and that your cache key is a string, and pushed it up onto a Git Gist here with the corresponding cache miss unit test as well. (I've used NUnit, but it isn't really relevant here)

Problem

I am trying to mock a method that returns a IEnumerable set of data, like a list of all codes. There is an Interface ISystemService.cs that contains this method, a service class called SystemService.cs that has the method definition. System under test is: ``` public static class CacheKeys { public const string ALLCURRENCYCODES = "CurrencyCodes"; } public interface ICacheManager { T Get<T>(string key); void Set(string key, object data, int cacheTime); void Clear(); } public interface ISessionManager { } public interface IApplicationSettings { string LoggerName { get; } int CacheTimeout { get; } } public class EFDbContext : DbContext { public DbSet<CurrencyCode> CurrencyCodes { get; set; } } public class CurrencyCode { public string Code { get; set; } public string Description { get; set; } public decimal CurrencyUnit { get; set; } public int? DecimalPlace { get; set; } public string BaseCurrencyCode { get; set; } } public interface ISystemService { IEnumerable<CurrencyCode> GetAllCurrencyCodes(); } //SystemService.cs public class SystemService : ISystemService { private readonly EFDbContext db; private readonly ICacheManager cacheManager; private readonly ISessionManager sessionManager; private readonly IApplicationSettings appSettings; public SystemService(EFDbContext dbContext, ICacheManager cacheManager, ISessionManager sessionManager, IApplicationSettings appSettings) { db = dbContext; this.cacheManager = cacheManager; this.sessionManager = sessionManager; this.appSettings = appSettings; } public IEnumerable<CurrencyCode> GetAllCurrencyCodes() { var allCurrencyCodes = cacheManager.Get<IEnumerable<CurrencyCode>>(CacheKeys.ALLCURRENCYCODES); if (allCurrencyCodes == null) { allCurrencyCodes = db.CurrencyCodes.ToList(); cacheManager.Set(CacheKeys.ALLCURRENCYCODES, allCurrencyCodes, appSettings.CacheTimeout); } return allCurrencyCodes; } ``` Test Method ``` [TestMethod] public void testCacheMiss() { List<CurrencyCode> currencycodes = new List<CurrencyCode>() { new CurrencyCode(){Id = 1, Code = "IND", Description = "India"}, new CurrencyCode(){Id = 2, Code = "USA", Description = "UnitedStates"}, new CurrencyCodes(){Id = 3, Code = "UAE", Description = "ArabEmirates"} }; var mockEfContext = new Mock<EFDbContext>(); var mockCacheManager = new Mock<ICacheManager>(); var mockSessionManager = new Mock<ISessionManager>(); var mockAppSettings = new Mock<IApplicationSettings>(); // Setups for relevant methods of the above here, e.g. to test a cache miss mockEfContext.SetupGet(x => x.CurrencyCodes) .Returns(currencycodes); // Canned currencies mockCacheManager.Setup(x => x.Get<IEnumerable<CurrencyCode>>(It.IsAny<string>())) .Returns<IEnumerable<CurrencyCodes>>(null); // Cache miss // Act var service = new SystemService(mockEfContext.Object, mockCacheManager.Object, mockSessionManager.Object, mockAppSettings.Object); var codes = service.GetAllCodes(); // Assert + Verify mockCacheManager.Verify(x => x.Get<IEnumerable<CurrencyCodes>>( It.IsAny<string>()), Times.Once, "Must always check cache first"); mockEfContext.VerifyGet(x => x.CurrencyCodes, Times.Once, "Because of the simulated cache miss, must go to the Db"); Assert.AreEqual(currencycodes.Count, codes.Count(), "Must return the codes as-is"); ``` Since the defined constructor does not accept one parameter, how to pass the object as parameter? Please advice

Original source