Mock Interface casting back to original class - c#

My MongoDbRepository has an interface called IRepository. So I am mocking the interface to set up the method which is UpdateOneAsync. However my MerchantConfigurationRepository can only take a MongoDbRepository object which is why I need to cast it. For some reason when I do this
(MongoDBRepository<MerchantConfigurationEntity>)dataAccess.Object
I get the error
Unable to cast object of type 'Castle.Proxies.IRepository`1Proxy' to
type 'Newgistics.Common.MongoDb.MongoDBRepository`1
How am I supposed to set up the Mock and then pass in the object, I tried setting a variable to the dataAccess.Object and passing in that variable, but if I do that the setup goes in as null.
Below you will find the unit test:
[Fact]
public async void UpdateMerchantSuccessPushesMerchantEntityToDataStore()
{
//Arrange
var originalMerchantConfig = ModelFactory.GetMerchant();
var merchants = new List<MerchantConfigurationEntity>();
var dataAccess = new Mock<IRepository<MerchantConfigurationEntity>>();
dataAccess.Setup(m => m.UpdateOneAsync(It.IsAny<MerchantConfigurationEntity>()))
.Callback((MerchantConfigurationEntity m) => merchants.Add(m))
.Returns(Task.FromResult(1));
var merchantRepo = new MerchantConfigurationRepository((MongoDBRepository<MerchantConfigurationEntity>)dataAccess.Object);
//Act
var result = await merchantRepo.UpdateMerchant(originalMerchantConfig);
//Assert
result.ShouldNotBeNull();
result.Sucess.ShouldBeTrue();
merchants.Count.ShouldBe(1);
merchants[0].merchantId.ShouldBe(originalMerchantConfig.merchantId);
}

Your classes should be dependent on abstractions and not on concretions for this very reason. MerchantConfigurationRepository should be dependent on IRepository<MerchantConfigurationEntity> and not the implementation MongoDBRepository<MerchantConfigurationEntity>
public class MerchantConfigurationRepository {
private readonly IRepository<MerchantConfigurationEntity> repository;
public MerchantConfigurationRepository(IRepository<MerchantConfigurationEntity> repositiry) {
this.repository = repository;
}
//...other code
public Task<int> UpdateMerchant(Merchant model) { ... }
}
That way now you have more flexibility to use the mocked repository when testing in isolation.
var merchantRepo = new MerchantConfigurationRepository(dataAccess.Object);
Just make sure that your DI knows to use the actual implementation in production.

Related

How can I use Moq here?

My WEB API project is using a Generic Repository that implements an interface like this:
public interface IGenericEFRepository<TEntity> where TEntity : class
{
Task<IEnumerable<TEntity>> Get();
Task<TEntity> Get(int id);
}
public class GenericEFRepository<TEntity> : IGenericEFRepository<TEntity>
where TEntity : class
{
private SqlDbContext _db;
public GenericEFRepository(SqlDbContext db)
{
_db = db;
}
public async Task<IEnumerable<TEntity>> Get()
{
return await Task.FromResult(_db.Set<TEntity>());
}
public async Task<TEntity> Get(int id)
{
var entity = await Task.FromResult(_db.Set<TEntity>().Find(new object[] { id }));
if (entity != null && includeRelatedEntities)
{
//Some Code
}
return entity;
}
}
Well now I want to test this service. for this I have used the following code:
public class CustomerControllerTest
{
CustomerController _controller;
ICustomerProvider _provider;
ICustomerInquiryMockRepository _repo;
public CustomerControllerTest()
{
_repo = new CustomerInquiryMockRepository();
_provider = new CustomerProvider(_repo);
_controller = new CustomerController(_provider);
}
[Fact]
public async Task Get_WhenCalled_ReturnsOkResult()
{
// Act
var okResult = await _controller.Get();
// Assert
Assert.IsType<OkObjectResult>(okResult);
}
[Fact]
public async Task GetById_UnknownCustomerIdPassed_ReturnsNotFoundResult()
{
// Act
var notFoundResult = await _controller.Get(4);
// Assert
Assert.IsType<NotFoundResult>(notFoundResult);
}
}
Which my tests are working fine by creating a fake non-generic service manually with mock data (In-Memory) like below, instead of using my real generic interface and it's implementation that uses my database as data-source:
public interface ICustomerInquiryMockRepository
{
Task<IEnumerable<CustomerDTO>> GetCustomers();
Task<CustomerDTO> GetCustomer(int customerId);
}
And it's implementation:
public class CustomerInquiryMockRepository : ICustomerInquiryMockRepository
{
public async Task<IEnumerable<CustomerDTO>> GetCustomers()
{
return await Task.FromResult(MockData.Current.Customers);
}
public async Task<CustomerDTO> GetCustomer(int CustomerId)
{
var Customer = await Task.FromResult(MockData.Current.Customers.FirstOrDefault(p => p.CustomerID.Equals(CustomerId)));
if (includeTransactions && Customer != null)
{
Customer.Transactions = MockData.Current.Transactions.Where(b => b.CustomerId.Equals(CustomerId)).ToList();
}
return Customer;
}
}
And the MockData.Current.Customers is just a simple fake (In-Memory) List of Customers. Long story short, the above tests are working fine, however I am feeling I have repeated my self a lot and so I have decided to use Moq library instead of creating fake service manually. For this purpose I have used Moq like this:
public class CustomerControllerTest
{
CustomerController _controller;
ICustomerProvider _provider;
//ICustomerInquiryMockRepository _repo;
Mock<ICustomerInquiryMockRepository> mockUserRepo;
public CustomerControllerTest()
{
mockUserRepo = new Mock<ICustomerInquiryMockRepository>();
//_repo = new CustomerInquiryMockRepository();
_provider = new CustomerProvider(mockUserRepo.Object);
_controller = new CustomerController(_provider);
}
[Fact]
public async Task Get_WhenCalled_ReturnsOkResult()
{
mockUserRepo.Setup(m => m.GetCustomers())
.Returns(Task.FromResult(MockData.Current.Customers.AsEnumerable()));
// Act
var okResult = await _controller.Get();
// Assert
Assert.IsType<OkObjectResult>(okResult);
}
[Fact]
public async Task GetById_UnknownCustomerIdPassed_ReturnsNotFoundResult()
{
//Arrange
I don't know how can I use Moq here and in the other parts of my tests
// Act
var notFoundResult = await _controller.Get(4);
// Assert
Assert.IsType<NotFoundResult>(notFoundResult);
}
Now my question is the Mock is working fine when I use it for Mocking the GetCustomers method because I simply paste the code from GetCustomers method in the CustomerInquiryMockRepository in the Returns method of the Mock object. However I don't really have any idea how can I use Mock for my other methods inside this Repository. Should I replace anything that I have in the Return method?
You can mock out your repository like so:
var mockUserRepo = new Mock<ICustomerInquiryMockRepository>();
mockUserRepo.Setup(x => x.GetCustomers())
.Returns(Task.FromResult(MockData.Current.Customers.AsEnumerable());
mockUserRepo.Setup(x => x.GetCustomer(It.IsAny<int>()))
.Returns(res => Task.FromResult(MockData.Current.Customers.ElementAt(res));
If you want to mock out specific values for GetCustomer, you can do:
mockUserRepo.Setup(x => x.GetCustomer(It.Is<int>(y => y == 4)))
.Returns(res => Task.FromResult(/* error value here */));
I think the key here is to use It.Is or It.IsAny based on how you want to mock out the object. Generally, you also want to mock out interfaces that are used in production code, instead of having production code depend on something with Mock or Test in the name. I would recommend against taking a production code dependency on something named ICustomerInquiryMockRepository, if that is indeed what you're doing and not just part of the MCVE you've provided.
Tests usually use mocking to test the workflow of an application at a high level, so you would usually want to mock out your services level, call a controller, and verify that the services were called as expected. For example:
// Production class sample
class ProductionController
{
public ProductionController(IService1 service1, IService2 service2) { }
public void ControllerMethod()
{
var service1Result = service1.Method();
service2.Method(service1Result);
}
}
// Test sample
// arrange
var expectedResult = new Service1Result();
var service1 = Mock.Of<IService1>(x => x.Method() == expectedResult);
var service2 = Mock.Of<IService2>(x => x.Method(It.Is<Service1Result>(y => y == expectedResult)));
var controller = new ProductionController(service1, service2);
// act
controller.ControllerMethod();
// assert
Mock.Get(service1).Verify(x => x.Method(), Times.Once);
Mock.Get(service2).Verify(x => x.Method(expectedResult), Times.Once);
As you can see from the example, you aren't checking the business logic of either of the services, you're just validating that the methods were called with the expected data. The test is built around verification of methods being called, not any particular branching logic.
Also, unrelated to your question, Moq also has a cool syntax you can use for simple mock setups:
var repo = Mock.Of<ICustomerInquiryMockRepository>(x =>
x.GetCustomers() == Task.FromResult(MockData.Current.Customers.AsEnumerable()));
You can use Mock.Get(repo) if you need to do additional setup on the repository. It's definitely worth checking out, I find it much nicer to read.

How to properly moq ExecuteQuery method within DataContext?

I'm having a difficult time trying to understand how to appropriately return mocked data from a simulated database call in a unit test.
Here's an example method I want to unit test (GetBuildings):
public class BuildingService : IBuildingService {
public IQueryable<Building> GetBuildings(int propertyId)
{
IQueryable<Building> buildings;
// Execution path for potential exception thrown
// if (...) throw new SpecialException();
// Another execution path...
// if (...) ...
using (var context = DataContext.Instance())
{
var Params = new List<SqlParameter>
{
new SqlParameter("#PropertyId", propertyId)
};
// I need to return mocked data here...
buildings = context
.ExecuteQuery<Building>(System.Data.CommandType.StoredProcedure, "dbo.Building_List", Params.ToArray<object>())
.AsQueryable();
}
return buildings;
}
}
So GetBuildings calls a stored procedure.
So I need to mock the DataContext, that of which I can override and set a testable instance. So what happens here is, in the above example DataContext.Instance() does return the mocked object.
[TestFixture]
public class BuildingServiceTests
{
private Mock<IDataContext> _mockDataContext;
[SetUp]
public void Setup() {
_mockDataContext = new Mock<IDataContext>();
}
[TearDown]
public void TearDown() {
...
}
[Test]
public void SomeTestName() {
_mockDataContext.Setup(r =>
r.ExecuteQuery<Building>(CommandType.StoredProcedure, "someSproc"))
.Returns(new List<Building>() { new Building() { BuildingId = 1, Title = "1" }}.AsQueryable());
DataContext.SetTestableInstance(_mockDataContext.Object);
var builings = BuildingService.GetBuildings(1, 1);
// Assert...
}
Please ignore some of the parameters, like propertyId. I've stripped those out and simplified this all. I simply can't get the ExecuteQuery method to return any data.
All other simple peta-poco type methods I can mock without issue (i.e. Get, Insert, Delete).
Update
DataContext.Instance returns the active instance of the DataContext class, if exists, and if not exists, returns a new one. So the method of test under question returns the mocked instance.
Do not mock DataContext. Because mocking DataContext will produce tests tightly coupled to the implementation details of DataContext. And you will be forced to change tests for every change in the code even behavior will remain same.
Instead introduce a "DataService" interface and mock it in the tests for BuildingService.
public interface IDataService
{
IEnumerable<Building> GetBuildings(int propertyId)
}
Then, you can tests implementation of IDataService agains real database as part of integration tests or tests it agains database in memory.
If you can test with "InMemory" database (EF Core or Sqlite) - then even better -> write tests for BuildingService against actual implementation of DataContext.
In tests you should mock only external resources (web service, file system or database) or only resources which makes tests slow.
Not mocking other dependencies will save you time and give freedom while you refactoring your codebase.
After update:
Based on the updated question, where BuildingService have some execution path - you can still testing BuildingService and abstract data related logic to the IDataService.
For example below is BuildingService class
public class BuildingService
{
private readonly IDataService _dataService;
public BuildingService(IDataService dataService)
{
_dataService = dataService;
}
public IEnumerable<Building> GetBuildings(int propertyId)
{
if (propertyId < 0)
{
throw new ArgumentException("Negative id not allowed");
}
if (propertyId == 0)
{
return Enumerable.Empty<Building>();
}
return _myDataService.GetBuildingsOfProperty(int propertyId);
}
}
In tests you will create a mock for IDataService and pass it to the constructor of BuildingService
var fakeDataService = new Mock<IDataContext>();
var serviceUnderTest = new BuildingService(fakeDataService);
Then you will have tests for:
"Should throw exception when property Id is negative"
"Should return empty collection when property Id equals zero"
"Should return collection of expected buildings when valid property Id is given"
For last test case you will mock IDataService to return expected building only when correct propertyId is given to _dataService.GetBuildingsOfProperty method
In order for the mock to return data is needs to be set up to behave as expected given a provided input.
currently in the method under test it is being called like this
buildings = context
.ExecuteQuery<Building>(System.Data.CommandType.StoredProcedure, "dbo.Building_List", Params.ToArray<object>())
.AsQueryable();
Yet in the test the mock context is being setup like
_mockDataContext.Setup(r =>
r.ExecuteQuery<Building>(CommandType.StoredProcedure, "someSproc"))
.Returns(new List<Building>() { new Building() { BuildingId = 1, Title = "1" }}.AsQueryable());
Note what the mock is told to expect as parameters.
The mock will only behave as expected when provided with those parameters. Otherwise it will return null.
Consider the following example of how the test can be exercised based on the code provided in the original question.
[Test]
public void SomeTestName() {
//Arrange
var expected = new List<Building>() { new Building() { BuildingId = 1, Title = "1" }}.AsQueryable();
_mockDataContext
.Setup(_ => _.ExecuteQuery<Building>(CommandType.StoredProcedure, It.IsAny<string>(), It.IsAny<object[]>()))
.Returns(expected);
DataContext.SetTestableInstance(_mockDataContext.Object);
var subject = new BuildingService();
//Act
var actual = subject.GetBuildings(1);
// Assert...
CollectionAssert.AreEquivalent(expected, actual);
}
That said, the current design of the system under test is tightly coupled to a static dependency which is a code smell and makes the current design follow some bad practices.
The static DataContext which is currently being used as a factory should be refactored as such,
public interface IDataContextFactory {
IDataContext CreateInstance();
}
and explicitly injected into dependent classes instead of calling the static factory method
public class BuildingService : IBuildingService {
private readonly IDataContextFactory factory;
public BuildingService(IDataContextFactory factory) {
this.factory = factory
}
public IQueryable<Building> GetBuildings(int propertyId) {
IQueryable<Building> buildings;
using (var context = factory.CreateInstance()) {
var Params = new List<SqlParameter> {
new SqlParameter("#PropertyId", propertyId)
};
buildings = context
.ExecuteQuery<Building>(System.Data.CommandType.StoredProcedure, "dbo.Building_List", Params.ToArray<object>())
.AsQueryable();
}
return buildings;
}
}
This will allow for a proper mock to be created in injected into the subject under test without using a static workaround hack.
[Test]
public void SomeTestName() {
//Arrange
var expected = new List<Building>() { new Building() { BuildingId = 1, Title = "1" }}.AsQueryable();
_mockDataContext
.Setup(_ => _.ExecuteQuery<Building>(CommandType.StoredProcedure, It.IsAny<string>(), It.IsAny<object[]>()))
.Returns(expected);
var factoryMock = new Mock<IDataContextFactory>();
factoryMock
.Setup(_ => _.CreateInstance())
.Returns(_mockDataContext.Object);
var subject = new BuildingService(factoryMock.Object);
//Act
var actual = subject.GetBuildings(1);
// Assert...
CollectionAssert.AreEquivalent(expected, actual);
}

Nunit testing with Mock. Instance of Interface

I have the following (simplified) code.
public class Controller
{
private readonly IService _service;
public Controller(IService service)
{
_service = service;
}
public async Task<IHttpActionResult> Create(MyObject object)
{
var result = _service.method(object);
if (!result.Succeeded)
{
return this.GetErrorResult(object);
}
}
}
and SimpleInjector is used to inject the dependency between _service and its implementation class, like this:
public static void Register(Container container)
{
container.Register<IService, Service>();
}
As a note, injection and unit testing are new to me so I do not fully understand them, but am learning.
If I run the application through Swagger, all is working fine.
As a note, the Register function is called when I run the application through Swagger.
Now, I am trying to setup some unit tests using NUnit, and am Mocking the IService object like this:
var Service = new Mock<IService>();
Controller _controller = new Controller(Service.Object);
_controller.Create(new MyObject object());
which seems to be correct to me so far - although I am not sure?
The problem is that for the unit test, result is always null - I think the is because there is a problem with my Mock of the interface - it does not seem to be finding the method - it never steps into it and does not show up int he debugger.
As a note, for the unit test, the Register method does not get called. I did try calling it to register the dependency, but it does not help.
As I said above, this is all new to me and I am on the edge of my understanding on all of this.
I am out of ideas and do not know where to look from here, so any help would be greatly appreciated.
EDIT:
The original question had the following:
public async Task<IHttpActionResult> Create(string content)
which I have updated to:
public async Task<IHttpActionResult> Create(MyObject object)
Can anyone advise how I can pass in a generic reference to MyObject on the setup, without having to make an instance of this class.
So basically I want to tell it that an instance of this class will be passed in, without creating that instance.
I have tried the following:
Service.Setup(x => x.method(It.IsAny<MyObject>())
but it says cannot convert MethodGroup to MyObject
and here is the definition of IService:
public interface IService
{
IdentityResult method(ApplicationUser user, UserLoginInfo login);
}
You need to configure the Mock object to return something for IService.method as follows:
var Service = new Mock<IService>();
Service.Setup(x => x.method(It.IsAny<string>())
.Returns<string>(str => **whatever result you need**);
With the addition of your actual IService definition, you should change the Setup call to:
Service.Setup(x => x.method(It.IsAny<ApplicationUser>(), It.IsAny<UserLoginInfo>())
.Returns<ApplicationUser, UserLoginInfo>((user, login) => new IdentityResult(true));
The setup method has to be called on the Mock object.
var Service = new Mock<IService>();
Service.Setup(x=>x.method("argument")).Returns(YourReturnObject)
Controller _controller = new Controller(Service.Object);
Using your simplified example
public class Controller
{
private readonly IService _service;
public Controller(IService service)
{
_service = service;
}
public async Task<IHttpActionResult> Create(string content)
{
var result = await _service.method(content);
if (!result.Succeeded)
{
return this.GetErrorResult(result);
}
return Ok();
}
}
Lets assume IService is defined as
public interface IService {
Task<Result> method(string input);
}
public class Result {
public bool Succeeded { get; set; }
}
For the unit test you need to setup the mock to fake the actions wanted for the test
public async Task Controller_Given_Content_Should_Return_Ok() {
//Arrange
var input = "content";
var mockService = new Mock<IService>();
mockService
.Setup(m => m.method(input))
.ReturnAsync(new Result { Succeeded = true });
var _controller = new Controller(mockService.Object);
//Act
var result = await _controller.Create(input);
//Assert
Assert.IsNotNull(result);
Assert.IsInstanceOfType(result,typeof(OkResult));
}
Given that the method under test is asynchronous you would want to setup the test to be asynchronous as well.

Mock lazy interface with Moq

I want mock lazy interface but I got object reference not set to an instance of an object exception.
‌Here is class under test:
public class ProductServiceService : IProductServiceService
{
private readonly Lazy<IProductServiceRepository> _repository;
private readonly Lazy<IProductPackageRepository> _productPackageRepository;
public ProductServiceService(
Lazy<IProductServiceRepository> repository,
Lazy<IProductPackageRepository> productPackageRepository)
{
_repository = repository;
_productPackageRepository = productPackageRepository;
}
public async Task<OperationResult> ValidateServiceAsync(ProductServiceEntity service)
{
var errors = new List<ValidationResult>();
if (!await _productPackageRepository.Value.AnyAsync(p => p.Id == service.PackageId))
errors.Add(new ValidationResult(string.Format(NameMessageResource.NotFoundError, NameMessageResource.ProductPackage)));
.
.
.
return errors.Any()
? OperationResult.Failed(errors.ToArray())
: OperationResult.Success();
}
}
and here is test class
[Fact, Trait("Category", "Product")]
public async Task Create_Service_With_Null_Financial_ContactPerson_Should_Fail()
{
// Arrange
var entity = ObjectFactory.Service.CreateService(packageId: 1);
var fakeProductServiceRepository = new Mock<Lazy<IProductServiceRepository>>();
var repo= new Mock<IProductPackageRepository>();
repo.Setup(repository => repository.AnyAsync(It.IsAny<Expression<Func<ProductPackageEntity, bool>>>()));
var fakeProductPackageRepository = new Lazy<IProductPackageRepository>(() => repo.Object);
var sut = new ProductServiceService(fakeProductServiceRepository.Object, fakeProductPackageRepository);
// Act
var result = await sut.AddServiceAsync(service);
// Assert
Assert.False(result.Succeeded);
Assert.Contains(result.ErrorMessages, error => error.Contains(string.Format(NameMessageResource.NotFoundError, NameMessageResource.ProductPackage)));
}
fakeProductPackageRepository always is null. I followed this blog post but still I'm getting null reference exception.
How to mock lazy initialization of objects in C# unit tests using Moq
Update:
here is a screen that indicates fakeProductPackageRepository is null.
Here is a refactored version of your example:
[Fact, Trait("Category", "Product")]
public async Task Create_Service_With_Null_Financial_ContactPerson_Should_Fail() {
// Arrange
var entity = ObjectFactory.Service.CreateService(packageId = 1);
var productServiceRepositoryMock = new Mock<IProductServiceRepository>();
var productPackageRepositoryMock = new Mock<IProductPackageRepository>();
productPackageRepositoryMock
.Setup(repository => repository.AnyAsync(It.IsAny<Expression<Func<ProductPackageEntity, bool>>>()))
.ReturnsAsync(false);
//Make use of the Lazy<T>(Func<T>()) constructor to return the mock instances
var lazyProductPackageRepository = new Lazy<IProductPackageRepository>(() => productPackageRepositoryMock.Object);
var lazyProductServiceRepository = new Lazy<IProductServiceRepository>(() => productServiceRepositoryMock.Object);
var sut = new ProductServiceService(lazyProductServiceRepository, lazyProductPackageRepository);
// Act
var result = await sut.AddServiceAsync(service);
// Assert
Assert.False(result.Succeeded);
Assert.Contains(result.ErrorMessages, error => error.Contains(string.Format(NameMessageResource.NotFoundError, NameMessageResource.ProductPackage)));
}
UPDATE
The following Minimal, Complete, and Verifiable example of your stated issue passes when tested.
[TestClass]
public class MockLazyOfTWithMoqTest {
[TestMethod]
public async Task Method_Under_Test_Should_Return_True() {
// Arrange
var productServiceRepositoryMock = new Mock<IProductServiceRepository>();
var productPackageRepositoryMock = new Mock<IProductPackageRepository>();
productPackageRepositoryMock
.Setup(repository => repository.AnyAsync())
.ReturnsAsync(false);
//Make use of the Lazy<T>(Func<T>()) constructor to return the mock instances
var lazyProductPackageRepository = new Lazy<IProductPackageRepository>(() => productPackageRepositoryMock.Object);
var lazyProductServiceRepository = new Lazy<IProductServiceRepository>(() => productServiceRepositoryMock.Object);
var sut = new ProductServiceService(lazyProductServiceRepository, lazyProductPackageRepository);
// Act
var result = await sut.MethodUnderTest();
// Assert
Assert.IsTrue(result);
}
public interface IProductServiceService { }
public interface IProductServiceRepository { }
public interface IProductPackageRepository { Task<bool> AnyAsync();}
public class ProductServiceService : IProductServiceService {
private readonly Lazy<IProductServiceRepository> _repository;
private readonly Lazy<IProductPackageRepository> _productPackageRepository;
public ProductServiceService(
Lazy<IProductServiceRepository> repository,
Lazy<IProductPackageRepository> productPackageRepository) {
_repository = repository;
_productPackageRepository = productPackageRepository;
}
public async Task<bool> MethodUnderTest() {
var errors = new List<ValidationResult>();
if (!await _productPackageRepository.Value.AnyAsync())
errors.Add(new ValidationResult("error"));
return errors.Any();
}
}
}
A Lazy<> as a parameter is somewhat unexpected, though not illegal (obviously). Remember that a Lazy<> wrapped around a service is really just deferred execution of a Factory method. Why not just pass the factories to the constructor? You could still wrap the call to the factory in a Lazy<> inside your implementation class, but then you can just fake / mock your factory in your tests and pass that to your sut.
Or, perhaps the reason that you're passing around a Lazy<> is because you're really dealing with a singleton. In that case, I'd still create a factory and take dependencies on the IFactory<>. Then, the factory implementation can include the Lazy<> inside of it.
Often, I solve the singleton requirement (without the lazy loading) via setting a custom object scope for the dependency in my IoC container. For instance, StructureMap makes it easy to set certain dependencies as singleton or per-request-scope in a web application.
I rarely need to assert that I've done a lazy initialization on some service inside of a system-under-test. I might need to verify that I've only initialized a service once per some scope, but that's still easily tested by faking the factory interface.
The thing is that you are creating a Mock of Lazy as fakeProductServiceRepository and later on are returning that instance where just a Mock is needed.
You should change
var fakeProductServiceRepository = new Mock<Lazy<IProductServiceRepository>>();
to
var fakeProductServiceRepository = new Mock<IProductServiceRepository>();

Unit Testing with DbContext mock through Service Layer

I'm a beginner at writing unit tests and I have a test I'm trying to get working. I'll start of by explaining what I'm trying to test.
I'm trying to test a method which saves messages in a Mvc 4 project. The method is called SaveMessage and is shown below.
namespace ChatProj.Service_Layer
{
public class UserService : IUserService
{
public MessageContext messageContext = new MessageContext();
public UserService()
{
_messageRepository = new MessageRepository(messageContext);
}
private IMessageRepository _messageRepository;
-> public void SaveMessage(Message message)
{
messageContext.Messages.Add(message);
_messageRepository.Save();
}
The _messageRepository.Save in the SaveMessage method is implemented in my DAL layer MessageRepository and looks like this:
public void Save()
{
context.SaveChanges();
}
This way of saving will seem a bit overcomplicated, but I structured the project this way because I didn't want the service layer (IUserService & UserService) to handle operations that could & should (i think) be handled by the Data Access Layer (IMessageRepository & MessageRepository).
Now comes the tricky part. I've been trying to understand how I could unit test this. This is my try:
namespace ChatProj.Tests
{
[TestFixture]
class MessageRepositoryTests
{
[SetUp]
public void Setup()
{
}
[Test]
public void SaveMessage_SaveWorking_VerifyUse()
{
//Arrange
var userServiceMock = new Mock<UserService>();
var message = new Message { MessageID = 0, Name = "Erland", MessageString = "Nunit Test", MessageDate = DateTime.Now };
var repositoryMock = new Mock<IMessageRepository>();
var contextMock = new Mock<MessageContext>();
MessageRepository messageRepository = new MessageRepository(contextMock.Object);
UserService userService = new UserService();
//Act
userService.SaveMessage(message);
//Assert
repositoryMock.Verify(m => m.Save());
userServiceMock.Verify(m => m.SaveMessage(message));
}
}
I get this error: Imgur link , and I'm not quite sure how to solve it. I've tried looking at several other SO posts but I fail to make the test work.
So I'm wondering, how do I practically get my Unit Test to work?
You should setup your MessageContext properties to return fake data and don't make real Db call with SaveChanges method.
Right now it still tries to access a real DB.
But you can setup only virtual properties or if it will be an inteface.
So the best solution is to extract an interface from your MessageContext and inject it into repository. Then you can easily mock your IMessageContext interface and force it to return appropriate in-memory data.
Take a look at these two lines:
UserService userService = new UserService();
//Act
userService.SaveMessage(message);
You're creating a userService instance, and then immediately saving your message. Now jump into the SaveMessage code.
public void SaveMessage(Message message)
{
messageContext.Messages.Add(message);
_messageRepository.Save();
}
Ok, now you're adding stuff to messageContext, and then calling _messageRepository.Save(). But where are messageContext and _messageRepository instantiated?
public MessageContext messageContext = new MessageContext();
public UserService()
{
_messageRepository = new MessageRepository(messageContext);
}
You're creating them at instantiation. The mocks that you've created in your test aren't being used. Instead of creating instances of these objects in the constructor, you might consider passing them into the UserService constructor as arguments. Then, you can pass in mocked instances in your test.

Categories

Resources