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