Unit testing and mocking domain objects - c#

I have a domain class, which looks like this:
public class Employee
{
public Guid EmployeeId { get; private set; }
public string Name { get; private set; }
public string Surname { get; private set; }
...
// other properties
public ICollection<Language> Languages { get; private set; }
= new List<Language>();
public ICollection<Skill> Skills { get; private set; }
= new List<Skill>();
public void AddLanguage(Language language)
{
if (language == null)
return;
Languages.Add(language);
}
public void DeleteLanguage(Guid languageId)
{
var languageToDelete = Languages
.SingleOrDefault(x => x.LanguageId == languageId);
if(languageToDelete == null)
throw new ArgumentException("Language entry doesn't exist.");
Languages.Remove(languageToDelete);
}
}
I would like to test given methods but I'm stuck.
I have:
[Fact]
public void AddLanguage_AfterCallWithValidObject_LanguagesCollectionContainsAddedObject()
{
var language = new Mock<Language>();
var employee = new Employee("Name", "Surname", ...);
employee.AddLanguage(language.Object);
Assert.Contains(employee.EmployeeLanguages, x => x.Language.Equals(language.Object));
}
[Fact]
public void DeleteLanguage_WhenLanguageWithGivenIdDoesntExist_ThrowArgumentException()
{
var languageToDelete = new Language("English");
var employee = new Mock<Employee>();
employee.Setup(x => x.Languages).Returns(new List<Languages>
{
new Language("Spanish"),
new Language("German")
});
employee.Object.DeleteLanguage(languageToDelete);
// Asserts here
}
In the first test I would like also assert that Languages.Add(skill) method was called but I have no idea how to do it.
Is it an elegant way to do it? I thought about mocking Add method but I'm not sure if it is a good idea.
In the second test I cannot simply mock Employee object as it is not an interface.
I thought about exposing Employee but I read I should not do that just for testing purpose.
How should I mock Languages property without exposing Employee as interface? Is it possible? Is it any good practice to do this kind of things?
Is my general concept for test these methods is okay? (I'm new in unit testing)

You should tests objects as "black box" without relying on implementation details. In your case implementation details is that Employee class uses ICollection.Add method.
And you definitely don't need to mock at all in your case.
Mock only dependencies which will make tests slow or very very very very complex to configure for the test.
[Fact]
public void AddLanguage_ShouldSaveGivenLanguage()
{
var language = new Language();
var employee = new Employee("Name", "Surname");
employee.AddLanguage(language);
var expectedLanguages = new[] { language };
employee.EmployeeLanguages.Should().BeEquivalentTo(expectedLanguages);
}
Use public API Employee class provide to setup it for the test (back box).
For testing DeleteLanguage add dummy languages through public API of the class.
[Fact]
public void DeleteLanguage_WhenLanguageExists_Remove()
{
var language1 = new Language("German");
var language2 = new Language("French");
var languageToDelete = new Language("English");
var employee = new Employee("Name", "Surname");
employee.AddLanguage(language1);
employee.AddLanguage(language2);
employee.AddLanguage(languageToDelete);
employee.DeleteLanguage(languageToDelete);
var expectedLanguages = new[] { language1, language2 };
employee.EmployeeLanguages.Should().BeEquivalentTo(expectedLanguages);
}
[Fact]
public void DeleteLanguage_WhenLanguageNotExists_ThrowException()
{
var language1 = new Language("German");
var language2 = new Language("French");
var notExistedLanguage = new Language("English");
var employee = new Employee("Name", "Surname");
employee.AddLanguage(language1);
employee.AddLanguage(language2);
Action delete = () => employee.DeleteLanguage(languageToDelete);
delete.Should()
.Throw<ArgumentException>()
.WithMessage("Language entry doesn't exist.");
}
Did you notice how cumbersome employee.EmployeeLanguages reads, you can rename property to just employee.Languages.
For readable assertions I used FluentAssertions library

For domain objects with very simple behavior and no dependencies, mocking isn't strictly needed. You can test Add simply with this:
//Arrange
var e = new Employee();
var l = new Mock<Language>();
//Act
e.AddLanguage(l.Object);
//Assert
Assert.IsTrue(e.Languages.Contains(l.Object));
Testing in this fashion you can achieve perfectly good code coverage and plenty of confidence that the Employee class works as designed.

Related

how to mock.SingleOrDefault() with Moq and C#

I've seen a few questions like this floating around but I'm looking for a good explination of how to get around this. I understand that Moq can't mock the extension call, but I'm just looking for a really good example. In the current code I there is a call like
var thing = listOfthings.myList.SingleOrDefault(lt => lt.Name== "NameToFind");
I've tried
MockedlistOfThings.Setup(x => x.myList.SingleOrDefault(o => o.Name == "NameToFind")).Returns(fakeObject);
Just looking for a good work around. thanks.
To further elaborate on how this situation came up, we are currently running a translation engine against large sets of data, that has to be run line by line. This translation engine passes in an Interface called IListOfthings. listOfthings is actually holding reference data in a dictionary that is preloaded in another call higher up in the program. I have created a "fakeObject" <- dictionary that holds my fake data that the method can use. I have Mocked the IlistOfthings which is passed in to the calling method. but I don't see how to fake the SingleOrDefault call.
Simplifed method below.
Public class ClassIMTesting
{
public void Translate(myObject obj, IlistOfThings listOfthings){
var thing = listOfthings.MyList.SingleOrDefault(lt => lt.Name== "NameToFind");
//Other logic here .....
}
}
public class Thing()
{
public string Name { get; set; }
public Dictionary MyDict { get; set; }
}
[TestFixture()]
public class MyCodeTest
{
MyObject myObj;
Mock<IListOfthings> listOfThings;
Thing thing;
[SetUp]
public void Setup()
{
myObj = new MyObject();
_thing = new thing();
_thing.Name = "MyName";
var myDict = new Dictionary<string, string>();
myDict.Add("70,~", "");
myDict.Add("70,145", "expectedResult");
myDict.Add("911,", "expectedResult");
thing.MyDict = myDict;
listOfThings = new Mock<IListOfthings>();
listOfThings.Setup(x => x.MyList.SingleOrDefault(o => o.Name == "MyName")).Returns(thing);
}
[TestCase("70", "~", "70070")]
[TestCase("70", "145", "expectedResult")]
[TestCase("911", "", "expectedResult")]
public void TranslateTest(string iTC, string ITCode, string expectedResult)
{
myObject.ITC = iTC;
myObject.ITCode = iTCode;
ClassIMTesting p = new ClassIMTesting();
p.Translate(myObject, listofThings.Object);
Assert.That(myObject.ITC3Code, Is.EqualTo(expectedResult));
}
}
public interface IListOfThings
{
List<Thing> MyList{ get; set; }
}
Given
public interface IListOfThings {
List<Thing> MyList { get; set; }
}
public class Thing() {
public string Name { get; set; }
public Dictionary MyDict { get; set; }
}
In order to provide a mock to satisfy the following example
public class ClassImTesting {
public Thing Translate(IlistOfThings listOfthings){
var thing = listOfthings.MyList.SingleOrDefault(lt => lt.Name== "NameToFind");
return thing
}
}
The mock just needs to return a collection that will allow the SingleOrDefault extension to behave as expected when invoked.
For example
//Arrrange
Mock<IListOfthings> listOfThings = new Mock<IListOfthings>();
var thing = new Thing {
Name = "NameToFind",
//...
};
List<Thing> list = new List<Thing>() { thing };
listOfThings.Setup(_ => _.MyList).Returns(list);
var subject = new ClassImTesting();
//Act
var actual = subject.Translate(listOfThings.Object);
//Assert
Assert.That(actual, Is.EqualTo(thing));
By having the mock return an actual List<Thing>, when
var thing = listOfthings.MyList.SingleOrDefault(lt => lt.Name== "NameToFind");
is invoked, the SingleOrDefault extension acts on a list where I can behave as expected.

How to mock nested properties and objects and their functions?

I have the code below which I would like to test, but I'm not sure whether it is possible or not.
I have EF repositories and they are put together to a class as public properties. I don't know exactly whether it is bad solution or not, but it is easier to manage the code and its dependencies. Only the testability is still a question.
Purpose of my test is injecting data via
administrationRepository.ModuleScreen.GetAll()
method and catch the result. I know that it can be tested once it is deployed, but I want the tests in build time in order to have as fast feedback as possible.
I went through questions and answers here, but I cannot find answers. In my code I got to the point where the property is set up, but when I call the administrationRepoMock.Object.ModuleScreen.GetAll() ReSharper offers only the methods coming from Entitiy Framework and not the Moq related functions.
It is possible what I want? If so, how? Is my design suitable for this? If not can you give me articles, urls where I can see examples?
Repository:
public interface IModuleScreen
{
IEnumerable<DomainModel.Administration.ModuleScreen> GetAll();
}
public interface IAdministrationRepository
{
IModuleScreen ModuleScreen { get; }
}
public partial class AdministrationRepository : IAdministrationRepository
{
public virtual IModuleScreen ModuleScreen { get; private set; }
public AdministrationRepository( IModuleScreen moduleScreen )
{
this.ModuleScreen = moduleScreen;
}
}
Application:
public partial class DigitalLibraryApplication : IDigitalLibraryApplication
{
private IAdministrationRepository _administrationRepository;
private IMapper.IMapper.IMapper _mapper;
private IDiLibApplicationHelper _dilibApplicationHelper;
#region Ctor
public DigitalLibraryApplication( IAdministrationRepository administrationRepository, IMapper.IMapper.IMapper mapper, IDiLibApplicationHelper diLibApplicationHelper)
{
_administrationRepository = administrationRepository;
_mapper = mapper;
_dilibApplicationHelper = diLibApplicationHelper;
}
#endregion
public IEnumerable<ModuleScreenContract> GetModuleScreens()
{
//inject data here
IEnumerable<ModuleScreen> result = _administrationRepository.ModuleScreen.GetAll();
List<ModuleScreenContract> mappedResult = _mapper.MapModuleScreenToModuleScreenContracts(result);
return mappedResult;
}
}
Test code:
[Test]
public void ItCalls_ModuleRepository_Get_Method()
{
List<SayusiAndo.DiLib.DomainModel.Administration.ModuleScreen> queryResult = new List<SayusiAndo.DiLib.DomainModel.Administration.ModuleScreen>()
{
new DomainModel.Administration.ModuleScreen()
{
Id = 100,
},
};
var moduleScreenMock = new Mock<IModuleScreen>();
moduleScreenMock.Setup(c => c.GetAll()).Returns(queryResult);
administrationRepoMock.SetupProperty(c => c.ModuleScreen, moduleScreenMock.Object);
var mapperMock = new Mock<IMapper.IMapper.IMapper>();
var dilibApplicationHerlperMock = new Mock<IDiLibApplicationHelper>();
IDigitalLibraryApplication app = new DigitalLibraryApplication( administrationRepoMock.Object, mapperMock.Object, dilibApplicationHerlperMock.Object );
app.GetModules();
//issue is here
administrationRepoMock.Object.ModuleScreen.GetAll() //???
}
Here is a refactoring of your test that passes when run. You can update the pass criteria to suit you definition of a successful test.
[Test]
public void ItCalls_ModuleRepository_Get_Method() {
// Arrange
List<ModuleScreen> queryResult = new List<ModuleScreen>()
{
new ModuleScreen()
{
Id = 100,
},
};
//Building mapped result from query to compare results later
List<ModuleScreenContract> expectedMappedResult = queryResult
.Select(m => new ModuleScreenContract { Id = m.Id })
.ToList();
var moduleScreenMock = new Mock<IModuleScreen>();
moduleScreenMock
.Setup(c => c.GetAll())
.Returns(queryResult)
.Verifiable();
var administrationRepoMock = new Mock<IAdministrationRepository>();
administrationRepoMock
.Setup(c => c.ModuleScreen)
.Returns(moduleScreenMock.Object)
.Verifiable();
var mapperMock = new Mock<IMapper>();
mapperMock.Setup(c => c.MapModuleScreenToModuleScreenContracts(queryResult))
.Returns(expectedMappedResult)
.Verifiable();
//NOTE: Not seeing this guy doing anything. What's its purpose
var dilibApplicationHerlperMock = new Mock<IDiLibApplicationHelper>();
IDigitalLibraryApplication app = new DigitalLibraryApplication(administrationRepoMock.Object, mapperMock.Object, dilibApplicationHerlperMock.Object);
//Act (Call the method under test)
var actualMappedResult = app.GetModuleScreens();
//Assert
//Verify that configured methods were actually called. If not, test will fail.
moduleScreenMock.Verify();
mapperMock.Verify();
administrationRepoMock.Verify();
//there should actually be a result.
Assert.IsNotNull(actualMappedResult);
//with items
CollectionAssert.AllItemsAreNotNull(actualMappedResult.ToList());
//There lengths should be equal
Assert.AreEqual(queryResult.Count, actualMappedResult.Count());
//And there should be a mapped object with the same id (Assumption)
var expected = queryResult.First().Id;
var actual = actualMappedResult.First().Id;
Assert.AreEqual(expected, actual);
}

Structuring test code

Currently we are trying to implement some unittesting on our services. In the below service an order is created and a audit registration is made about the creation of an order. When writing the two tests (because we think the tests should be seperated to get tests with 1 responsibility) this was where I started with:
public class TestPacklineOrderManagementService
{
[Fact]
public void CreateNewProductWhenNoPacklineOrderIsAvailable()
{
IPackLineOrderRepository packLineOrderRepository = Substitute.For<IPackLineOrderRepository>();
packLineOrderRepository.GetActive(Arg.Any<PackLine>()).Returns(x => null);
var rawProductRepository = Substitute.For<IRawProductRepository>();
rawProductRepository.Get(1).Returns(new RawProduct {Id = 1});
var packlineRepository = Substitute.For<IPackLineRepository>();
packlineRepository.Get(1).Returns(new PackLine {Id = 1});
var auditRegistrationService = Substitute.For<IAuditRegistrationService>();
var packlineOrderManagementService = new PacklineOrderManagementService(packLineOrderRepository, rawProductRepository, packlineRepository, auditRegistrationService);
packlineOrderManagementService.SetProduct(1,1);
packLineOrderRepository.Received()
.Insert(Arg.Is<PackLineOrder>(x => x.PackLine.Id == 1 && x.Product.Id == 1));
}
[Fact]
public void AuditCreateNewProductWhenNoPacklineOrderIsAvailable()
{
IPackLineOrderRepository packLineOrderRepository = Substitute.For<IPackLineOrderRepository>();
packLineOrderRepository.GetActive(Arg.Any<PackLine>()).Returns(x=>null);
var rawProductRepository = Substitute.For<IRawProductRepository>();
rawProductRepository.Get(1).Returns(new RawProduct { Id = 1 });
var packlineRepository = Substitute.For<IPackLineRepository>();
packlineRepository.Get(1).Returns(new PackLine { Id = 1 });
var auditRegistrationService = Substitute.For<IAuditRegistrationService>();
var packlineOrderManagementService = new PacklineOrderManagementService(packLineOrderRepository, rawProductRepository, packlineRepository, auditRegistrationService);
packlineOrderManagementService.SetProduct(1, 1);
auditRegistrationService.Received()
.Audit(Arg.Is<PackLineOrderAudit>(item => item.Action == PackLineOrderAction.CreatePacklineOrder));
}
}
As you can see a lot of duplicate code. To prevent this I tried to refactor this and it resulted in the code below:
public class TestPacklineOrderManagementService2
{
[Fact]
public void CreateNewProductWhenNoPacklineOrderIsAvailable()
{
IPackLineOrderRepository packLineOrderRepository;
IAuditRegistrationService auditRegistrationService;
var packlineOrderManagementService = BuilderForCreateNewProductWhenNoPacklineOrderIsAvailable(out packLineOrderRepository, out auditRegistrationService);
packlineOrderManagementService.SetProduct(1,1);
packLineOrderRepository.Received().Insert(Arg.Any<PackLineOrder>());
}
[Fact]
public void AuditCreateNewProductWhenNoPacklineOrderIsAvailable()
{
IPackLineOrderRepository packLineOrderRepository;
IAuditRegistrationService auditRegistrationService;
var packlineOrderManagementService = BuilderForCreateNewProductWhenNoPacklineOrderIsAvailable(out packLineOrderRepository, out auditRegistrationService);
packlineOrderManagementService.SetProduct(1, 1);
auditRegistrationService.Received()
.Audit(Arg.Is<PackLineOrderAudit>(item => item.Action == PackLineOrderAction.CreatePacklineOrder));
}
private PacklineOrderManagementService BuilderForCreateNewProductWhenNoPacklineOrderIsAvailable(out IPackLineOrderRepository packLineOrderRepository,
out IAuditRegistrationService auditRegistrationService)
{
packLineOrderRepository = CreatePackLineOrderRepository(x => null);
auditRegistrationService = CreateAuditRegistrationService();
var rawProductRepository = CreateRawProductRepository(x => new RawProduct { Id = 1 });
var packlineRepository = CreatePacklineRepository(x => new PackLine { Id = 1 });
var packlineOrderManagementService = new PacklineOrderManagementService(packLineOrderRepository,
rawProductRepository, packlineRepository, auditRegistrationService);
return packlineOrderManagementService;
}
private IPackLineOrderRepository CreatePackLineOrderRepository(Func<CallInfo, PackLineOrder> getActiveResult)
{
IPackLineOrderRepository packLineOrderRepository = Substitute.For<IPackLineOrderRepository>();
packLineOrderRepository.GetActive(Arg.Any<PackLine>()).Returns(getActiveResult);
return packLineOrderRepository;
}
private IRawProductRepository CreateRawProductRepository(Func<CallInfo, RawProduct> getResult)
{
IRawProductRepository rawProductRepository = Substitute.For<IRawProductRepository>();
rawProductRepository.Get(1).Returns(getResult);
return rawProductRepository;
}
private IPackLineRepository CreatePacklineRepository(Func<CallInfo, PackLine> getResult)
{
IPackLineRepository packLineRepository = Substitute.For<IPackLineRepository>();
packLineRepository.Get(1).Returns(getResult);
return packLineRepository;
}
private IAuditRegistrationService CreateAuditRegistrationService()
{
return Substitute.For<IAuditRegistrationService>();
}
}
Is there any way to get a better code base for our unittests?
Better is very subjective, it depends a lot on how you define it. Some people might argue that your first example was better since all of the setup code is together in your test. I do have some feedback based on your code above though...
When you're writing tests, don't use the same value for two parameters to your system under test (SUT) unless they really are the same, it hides transposition errors. So, in your test, you're setting up one of your substitutes like this:
rawProductRepository.Get(1).Returns(new RawProduct {Id = 1});
Then calling your SUT:
packlineOrderManagementService.SetProduct(1,1);
Are the 1s in the SUT call related to the Repository setup? It's not at all clear which 1 is which...
This somewhat subjective, but if your test setup is exactly the same, do you really need to duplicate the test, with different asserts? Does it really make sense for the Audit to take place if the Insert hasn't etc?
If you do have groups of tests that have similar setups, then you could push the common bits into your classes constructor. You could also organise your tests using nested classes, something like this:
public class TestPacklineOrderManagementService
{
public class TestSetProduct {
IPackLineOrderRepository _packLineOrderRepository;
IRawProductRepository _rawProductRepository;
// etc
public TestSetProduct() {
_packLineOrderRepository = Substitute.For<IPackLineOrderRepository>();
_packLineOrderRepository.GetActive(Arg.Any<PackLine>()).Returns(x => null);
_rawProductRepository = Substitute.For<IRawProductRepository>();
// etc
}
[Fact]
public void CreateNewProductWhenNoPacklineOrderIsAvailable()
{
// Any test specific setup...
_packlineOrderManagementService.SetProduct(1,1);
_packLineOrderRepository.Received()
.Insert(Arg.Is<PackLineOrder>(x => x.PackLine.Id == 1
&& x.Product.Id == 1));
}
[Fact]
public void AuditCreateNewProductWhenNoPacklineOrderIsAvailable()
{
_packlineOrderManagementService.SetProduct(1, 1);
_auditRegistrationService.Received()
.Audit(Arg.Is<PackLineOrderAudit>(item =>
item.Action == PackLineOrderAction.CreatePacklineOrder));
}
}
public class TestSomeOtherScenario {
// tests...
}
}
This approach and make your tests more succinct and easier to follow, if they only contain the test specific information, but is it better? It's very subjective, some people (including the xunit team) don't like shared per test setups. Really it's about finding the approach that works for you and your team...

Setup for testing a Linq query on a LinqToExcel IExcelQueryFactory

Using c#, Moq, MSTest, LinqToExcel
I'm having trouble figuring out the best way to Setup() a mock for a response from a Linq query on a Linq-to-Excel IExcelQueryFactory.
I think I should expect the Linq Query to return something of type delegate, but I'm not quite sure what that should look like
Can anyone suggest what my Return() should look like in the Moq Setup() below?
Also, any toughts on my approach to testing and mocking these Lynq methods? Should I be approaching this differently?
Thanks! I'm going to go book up on delegates now. :)
The Test
[TestClass]
public class ThingsSheetTests
{
[TestMethod]
public void GetRows_ReturnsListOfThings()
{
// Arrange
var mockExcelQueryFactory = new Mock<IExcelQueryFactory>();
var thingsSheet = new ThingsSheet(mockExcelQueryFactory.Object, "file", "worksheet");
mockExcelQueryFactory
.Setup(x => x.Worksheet<Thing>(It.IsAny<string>))
// I think this is correctly casting to a delegate
// however ExelQuerable constructor needs arguments:
// public ExcelQueryable(IQueryProvider provider, Expression expression);
// looking into what kind of IQueryProvider and Expression I should supply.
.Returns(Action(() => new ExcelQueryable<Thing> { })); // getting closer!
// Act
thingsSheet.GetRows();
// Assert
mockExcelQueryFactory.Verify();
}
}
The Class and Method I'm testing
public class ThingsSheet
{
private string importFile;
private string worksheetName;
private IExcelQueryFactory excelQueryFactory;
public ThingsSheet(IExcelQueryFactory excelQueryFactory, string importFile, string worksheetName)
{
this.excelQueryFactory = excelQueryFactory;
this.importFile = importFile;
this.worksheetName = worksheetName;
this.AddMappings();
}
private void AddMappings()
{
excelQueryFactory.AddMapping<Thing>(t => t.Id, "Thing ID");
}
public List<Thing> GetRows()
{
excelQueryFactory.AddMapping<Thing>(t => t.Id, "Thing ID");
var things = from thing in excelQueryFactory.Worksheet<Thing>(this.worksheetName)
select new Thing { };
return things.ToList<Thing>();
}
}
You can use e.g. a method which returns your fake data.
mockExcelQueryFactory
.Setup(x => x.Worksheet<Thing>(It.IsAny<string>()))
.Returns(ExcelQueryableOfThing());
Lets say Thing class looks like this:
public class Thing
{
public string Id { get; set; }
public string Name { get; set; }
}
Then in the method ExcelQueryableOfThing() you have to mock the CreateQuery<TElement>(Expression expression) method of IQueryProvider provider. Something like this:
private ExcelQueryable<Thing> ExcelQueryableOfThing()
{
var things = new List<Thing>
{
new Thing
{
Id = "1",
Name = "Adam"
},
new Thing
{
Id = "1",
Name = "Eva"
}
}
.AsQueryable();
Mock<IQueryProvider> queryProvider = new Mock<IQueryProvider>();
queryProvider
.Setup(p => p.CreateQuery<Thing>(It.IsAny<Expression>()))
.Returns(() => things);
Expression expressionFake = Expression.Constant(new List<Thing>().AsQueryable());
return new ExcelQueryable<Thing>(queryProvider.Object, expressionFake);
}
Then in the unit test thingsSheet.GetRows() will return your fake data (Adam and Eva :). HTH
[TestMethod]
public void GetRows_ReturnsListOfThings()
{
// Arrange
Mock<IExcelQueryFactory> mockExcelFile = new Mock<IExcelQueryFactory>();
var thingsSheet = new ThingsSheet(mockExcelFile.Object, "file", "worksheet");
mockExcelFile
.Setup(x => x.Worksheet<Thing>(It.IsAny<string>()))
.Returns(ExcelQueryableOfThing());
// Act
List<Thing> rows = thingsSheet.GetRows();
// Assert
Assert.AreEqual(2, rows.Count); // Adam and Eva
}

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

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
If CodeService is under test, then you want to be mocking its dependencies, not the CodeService itself.
You'll need to provide Mocks 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)
allCodes is your service.. its the mock you need to be working with. You shouldn't be creating a concrete instance of your ICodeService.. your mock exists to fill that role.
So, remove this:
var service = new CodeService(allCodes.object);
Your next line should be:
var code = allCodes.Object.GetAllCodes();
But then.. this test seems completely redundant after that.. since you appear to be testing your mock..
Also, allCodes should be called serviceMock.. as that makes more sense.

Categories