Mocking class with multiple interfaces - c#

I am trying to test a method that is using two different interfaces.
Using Moq I configure the interfaces methods and set a return object, but just the first method executed returns value, the second returns null, no matter what I set as Returns.
This is an example :
Interface 1
public interface IUserRepository
{
User GetUserById(int id);
}
Interface 2
public interface ICallApiService
{
ApiResponseDto ValidateUser();
}
Class I want to test
public class UserServices : IUserServices
{
private IUserRepository _userRepository;
private ICallApiService _callApiService;
public UserServices(IUserRepository userRepository, ICallApiService callApiService)
{
_userRepository = userRepository;
_callApiService = callApiService;
}
public User GetUserById(int id)
{
//result always have a value set to result
var result = _callApiService.ValidateUser();
//result2 is always null
var result2 = _userRepository.GetUserById(result.UserId);
return result2;
}
}
The Test Method
[TestMethod]
public void TestMethod1()
{
moqUserRepository = new Moq.Mock<IUserRepository>();
moqUserRepository.Setup(s => s.GetUserById(1)).Returns(new User() { Id = 100, Birth = DateTime.Now, Email = "g#test.com", Name="g" });
moqCallApiService = new Moq.Mock<ICallApiService>();
moqCallApiService.Setup(s => s.ValidateUser()).Returns(new ApiResponseDto() { Active = true, Messages = "None", UserId = 100 });
var userService = new UserServices(moqUserRepository.Object, moqCallApiService.Object);
var resultInstance = userService.GetUserById(1);
var moqUserService = new Moq.Mock<UserServices>(moqUserRepository.Object, moqCallApiService.Object).Object;
var resultMock = moqUserService.GetUserById(1);
}
In both cases using instance and mock i get the same error (return null).
Am I missing something to Moq ?

You're instructing the repository mock to return an object when the input parameter id has the value 1. But the service code calls the repository with the value of result.UserId which is set to be 100 by the other mock setup call.
Change the first setup call to
moqUserRepository.Setup(s => s.GetUserById(100)).Returns(new User() { Id = 100, Birth = DateTime.Now, Email = "g#test.com", Name="g" });
Or use It.IsAny, since you don't really care about the value when you only have a single mocked call to the method:
moqUserRepository.Setup(s => s.GetUserById(It.IsAny<int>())).Returns(new User() { Id = 100, Birth = DateTime.Now, Email = "g#test.com", Name="g" });

Related

I am writing the unit test for method inside which calls internal method. How can we mock the internal method?

Here is my code:
public IActionResult Post([FromBody] ApiPermission apiClient)
{
return Ok(_apiPermissionService.Add(apiClient, GetCurrentUserFullName(_httpContextAccessor.HttpContext.User)));
}
I need the result of GetCurrentUserFullName which has the definition of
internal string GetCurrentUserFullName(ClaimsPrincipal principal)
{
if (principal == null)
throw new ArgumentNullException(nameof(principal));
return principal.FindFirstValue("UserFullName");
}
How we can pass GetCurrentUserFullName to pass the test.
Below is my testing code:
public void Post()
{
Mock<ApiPermissionGroup> mockApiPermissionGroup = new Mock<ApiPermissionGroup>();
var apiPermission = new ApiPermission
{
ApiPermissionId = 1,
Name = "Name",
Description = "Description",
AddedBy = "AddedBy",
AddedDate = DateTime.UtcNow,
ModifiedBy = "ModifiedBy",
ModifiedDate = DateTime.UtcNow,
ApiPermissionGroupId = 2,
ApiPermissionGroup = mockApiPermissionGroup.Object
};
List<ApiPermission> lstApiPermission = new List<ApiPermission>();
lstApiPermission.Add(apiPermission);
ApiPermissionController ApiPermissionController = new ApiPermissionController(_mockApiPermissionService.Object, _mockHttpContextAccessor.Object);
var result = ApiPermissionController.Post(apiPermission);
Assert.IsNotNull(result);
}
When running the above code I am getting the error " System.NullReferenceException : Object reference not set to an instance of an object." at
Microsoft.AspNetCore.Http.IHttpContextAccessor.HttpContext.get returned null.
In this specific case, I'd not mock the internal method, but mock the context accessor, e.g.:
// Set up mock principal
var principal = new Mock<ClaimsPrincipal>();
principal
.Setup(r => r.FindFirst("UserFullName"))
.Returns(new Claim("UserFullName", "TEST_USER_NAME"));
// Create dummy context
var context = new DefaultHttpContext { User = principal.Object };
// Set up mock context accessor
var mockCtxAcc = new Mock<IHttpContextAccessor>();
mockCtxAcc.SetupGet(x => x.HttpContext).Returns(context);
// Create controller under test
var ctrl = new MyController(mockCtxAcc.Object, ...);
The unit test should test the behavior of the class as it is, but without the dependencies of the class. This way, you test the code that the controller runs in real life scenario - also the internal method as it is.

FakeItEasy to mock an object-modifying method

I am trying to write a unit test for a method that relies on a dependency which offers a method that accepts an object and modifies it, but does not return it on a "new path", e.g. as a return value or on a by reference parameter.
public class Product
{
public string Name { get; set; }
}
public interface IFixer
{
void Modify(Product product);
}
public class Fixer: IFixer
{
public void Modify(Product product)
{
if (string.IsNullOrEmpty(product.Name))
{
product.Name = "Default";
}
}
}
public class Manager()
{
private readonly IFixer _fixer;
public Manager(IFixer fixer)
{
_fixer = fixer;
}
public bool IsProductNew(int id)
{
var product = GetProduct(id); // Gets an object instance from a repository, e.g. a file or a database, so we can have something to operate on.
_fixer.Modify(product);
return product.Name != "Default";
}
}
So I want to be able to test my Manager class' IsProductNew() method:
var fakeFixer = A.Fake<IFixer>();
var manager = new Manager(fakeFixer);
var isNew = manager.IsProductNew(A<int>._);
Assert.True(isNew);
What I am missing here is: How do I mock the behaviour of IFixer.Modify(), i.e. have it modify a Product object instance?
Answering this effectively is dependent on the definition of GetProduct(id);
If however the IFixer implementation has no knock on effects or undesirable behavior then there really is no need to mock it.
//Arrange
var fixer = new Fixer();
var manager = new Manager(fixer);
//Act
var isNew = manager.IsProductNew(1);
//Assert
Assert.True(isNew);
But to answer
How do I mock the behaviour of IFixer.Modify(), i.e. have it modify a Product object instance?
you would need a callback that captures the matched parameter
//Arrange
var fakeFixer = A.Fake<IFixer>();
A.CallTo(() => fakeFixer.Modify(A<Product>._))
.Invokes((Product arg) => arg.Name = "Not Default Name");
var manager = new Manager(fakeFixer);
//Act
var isNew = manager.IsProductNew(1);
//Assert
Assert.True(isNew);
Reference Invoking Custom Code
So I want to be able to test my Manager class' IsProductNew() method
You cannot test it effectively in its current form. You will not get 100% coverage. You should either:
pass the product directly:
public bool IsProductNew(Product product)
{
_fixer.Modify(product);
return product.Name != "Default";
}
which you can test by:
var fakeFixer = A.Fake<IFixer>();
var manager = new Manager(fakeFixer);
var product = new Product { Id = 100, Name = "Default" }; // create another test for where Name != "Default"
var isNew = manager.IsProductNew(product);
// Assert that fixer.modify is called with the product
A.CallTo(() => fakeFixer.Modify(A<product>.That.Matches(p => p.Id == 100))).ShouldHaveBeenCalledOnceExactly();
// Should return false because of product name = "Default"
Assert.IsFalse(isNew);
or, pass a "product getter" into the Manager() constructor:
public Manager(IFixer fixer, IProductGetter productGetter)
{
_fixer = fixer;
_productGetter = productGetter;
}
...
public bool IsProductNew(int id)
{
var product = _productGetter.GetProduct(id);
_fixer.Modify(product);
return product.Name != "Default";
}
which you can test by:
var fakeProductGetter = A.Fake<IProductGetter>();
// Prime the product getter to return a product
A.CallTo(() => fakeProductGetter.Get(A<int>.Ignored))
.Returns(new Product{
Id = 100,
Name = "Default" // create another test for where Name != "Default"
});
var fakeFixer = A.Fake<IFixer>();
var manager = new Manager(fakeFixer, fakeproductGetter);
var isNew = manager.IsProductNew(100);
// Assert that a call is made to productGetter.Get with the ID
A.CallTo(() => productGetter.Get(100)).MustHaveHapennedOnceExactly();
// Assert that fixer.modify is called with the product
A.CallTo(() => fakeFixer.Modify(A<product>.That.Matches(p => p.Id == 100))).ShouldHaveBeenCalledOnceExactly();
// Should return false because of product name = "Default"
Assert.IsFalse(isNew);
The choice you make depends on whether you want the IsProductNew() method to be responsible for getting the product by the ID, or if you want to just pass the product directly.

Moq Insert/Update with new Object initialization

public class UserService
{
IUserRepo userRepo;
UserService(IUserRepo repo)
{
userRepo = repo;
}
void AddUser(JsonData data)
{
User user = new User()
{
Name = data.name,
Number = data.Number
};
userRepo.Insert(user);
int id = user.id;
}
}
id is 0 when a unit test case is debugged, but when it is a proper call it returns proper primary key i.e. 1, 2, 3, etc.
Mock
class TestCases
{
Mock<IUserRepo> mockUserRepo = new Mock<IUserRepo>();
[Test]
public void test1()
{
//Arrange
JsonData obj = new JsonData()
{
Name = "Jane",
Number = "0563722992"
}
User dumpUser= new User()
{
Name = "Def",
Number = "8111"
};
mockUserRepo
.Setup(x => x.Insert(It.IsAny<User>()))
.Callback(() => dumpUser.Id = 1);
//Act
UserService u = new UserService(mockUserRepo.Object);
u.AddUser(obj);
//Assert
}
}
While debugging the unit test it seems that callback is unable to change the id to 1 when it passes through the method Insert().
Can anybody help how to tackle with this issue?
There is no need for
User dumpUser= new User()
{
Name = "Def",
Number = "8111"
};
As the method under test creates/initializes it's own instance within.
Capture the passed argument in the call back and update the desired member there
//...
userRepo
.Setup(x => x.Insert(It.IsAny<User>()))
.Callback((User arg) => arg.Id = 1);
//...

Return the result of a mocked method to another mocked method

I've got a class that has the following implementation:
public sealed class HotelRepository : IHotelRepository
{
private readonly string _dataSource;
public HotelRepository(string dataSource) => _dataSource = dataSource;
/// <inheritdoc />
public async Task<IEnumerable<Hotel>> GetAllAsync() =>
await Task.Run(() => JObject.Parse(File.ReadAllText(_dataSource))["hotels"].ToList().Select(x => x.ToObject<Hotel>()));
/// <inheritdoc />
public async Task<IEnumerable<Hotel>> GetListByMatchAsync(string name) =>
await GetAllAsync().ContinueWith(x => x.Result.Where(y => y.Name.Contains(name, StringComparison.CurrentCultureIgnoreCase)));
}
As you can see, the GetListByMatchAsync method calls GetAllAsync, then does some logic before returning the result.
When I tried to mock this repository for unit testing, I'm struggling to get a result out of GetListByMatchAsync as it always fails as a null reference exception.
Here's the unit test:
[TestCase("Test", "X")]
[TestCase("Hotel", "X")]
[TestCase("Name", "X")]
public async Task GetListByMatchAsync_GetHotelListByMatchingNameAsync_ReturnsFiveMatchingHotels(string name, string nonMatch)
{
_hotelRepositoryMock = new Mock<IHotelRepository>();
_hotelRepository = _hotelRepositoryMock.Object;
// Set up sample data.
var data = new List<Hotel>
{
new Hotel{Id = 1, Name = $"{name}", Description = "Description2", Location = "Location2", Rating = Rating.Two},
new Hotel{Id = 2, Name = $"{name.ToUpper()}", Description = "Description1", Location = "Location1", Rating = Rating.Five},
new Hotel{Id = 3, Name = $"{name.ToLower()}", Description = "Description2", Location = "Location2", Rating = Rating.Three},
new Hotel{Id = 4, Name = $"{name} {nonMatch}", Description = "Description2", Location = "Location2", Rating = Rating.One},
new Hotel{Id = 5, Name = nonMatch, Description = "Description2", Location = "Location2", Rating = Rating.One},
};
// Set up mock methods and ensure these method returns any sample data.
_hotelRepositoryMock.Setup(x => x.GetListByMatchAsync(It.IsAny<string>()));
_hotelRepositoryMock.Setup(x => x.GetAllAsync()).ReturnsAsync(data);
var result = await _hotelRepository.GetListByMatchAsync(name);
// Cast to list to make assertions.
var hotels = result.ToList();
Assert.That(hotels, Is.TypeOf<List<Hotel>>());
Assert.That(hotels.Count, Is.EqualTo(4));
}
How can I make this test work such that the GetListByMatchAsync mock method does some logic after calling the mocked GetAllAsync method?
First, the code that you have shown cannot possibly work because the methods that you are trying to set up are not virtual. Declare the methods you want to Setup as virtual.
Second, this is wrong:
_hotelRepositoryMock.Setup(x => x.GetListByMatchAsync(It.IsAny<string>()));
With this call, you're effectively setting up GetListByMatchAsync to return default(Task<IEnumerable<Hotel>>), i.e. null. That's obviously not what you want. Either:
use .Returns(...) to specify what the method should return; or,
use .CallBase() if the method should simply return whatever the implementation in the base class would return. (This is likely what you need.)

Mock method of system-under-test with Moq

I have the following three methods in the CompanyApplication class (along with the supporting factories and services listed):
public ResultSet<CompanyDto> AddCompany(CompanyDto companyDto)
{
var result = new CompanyDto();
var company = new Company();
Mapper.Map(companyDto, company);
using (ITransaction t = _transactionFactory.Create())
{
company = _companyService.Add(company);
t.Commit();
}
Mapper.Map(company, result);
return new ResultSet<CompanyDto>(1, new[] { result });
}
public ResultSet<CompanyContactDto> AddCompanyContact(CompanyContactDto companyContactDto)
{
var result = new CompanyContactDto();
var company = new Company();
var contact = new CompanyContact();
Mapper.Map(companyContactDto, contact);
using (ITransaction t = _transactionFactory.Create())
{
var contactCompanies = FindByIdJoin<Company, CompanyDto>(companyContactDto.CompanySK);
Mapper.Map(contactCompanies.Data.First(), company);
company.CompanyContacts.Add(contact);
company = _companyService.Update(company);
t.Commit();
}
Mapper.Map(contact, result);
return new ResultSet<CompanyContactDto>(1, new[] { result });
}
public ResultSet<T_DtoType> FindByIdJoin<T_DbType, T_DtoType>(long id)
{
IAbstractRepository<T_DbType> repository = EnsureRepository<T_DbType>();
T_DbType entity = repository.FindByIdJoin(id);
return (entity == null ? null : MapResultSetToDto<T_DbType, T_DtoType>(entity));
}
There are other objects in play here, which is why the FindByIdJoin has been made a separate method in the CompanyApplication class.
I have set up the testing class with some mocks and an instance of the CompanyApplication class:
private Mock<ICompanyRepository> _mockCompanyRepository;
private Mock<ICompanyDomain> _mockCompanyService;
private Mock<ITransactionFactory> _mockTransactionFactory;
private Mock<ITransaction> _mockTransaction;
private CompanyApplication _companyApplication;
[Setup]
public void SetUp()
{
_mockCompanyRepository = new Mock<ICompanyRepository>(MockBehavior.Strict);
_mockCompanyService = new Mock<ICompanyDomain>(MockBehavior.Strict);
_mockTransactionFactory = new Mock<ITransactionFactory>(MockBehavior.Strict);
_mockTransaction = new Mock<ITransaction>(MockBehavior.Strict);
_companyApplication = new CompanyApplication(
_mockCompanyRepository.Object,
_mockCompanyService.Object,
_mockTransactionFactory.Object);
}
I am successfully able to test the FindByIdJoin and AddCompany methods directly in Moq like this:
[Test]
public void CanFindCompanyByIdJoin()
{
var data = new Company {ObjectId = 1, Name = "Company1"};
_mockCompanyRepository.Setup(x => x.FindByIdJoin(It.Is<long>(arg => arg == data.ObjectId)))
.Returns(data);
var result = _companyApplication.FindByIdJoin<Company, CompanyDto>(data.ObjectId);
Assert.AreEqual(data.ObjectId, result.Data.First().ObjectId);
}
[Test]
public void CanAddCompany()
{
var data = new Company {ObjectId = 1, Name = "Company1"};
_mockCompanyService.Setup(x => x.Add(It.Is<Company>(arg => arg.ObjectId == data.ObjectId)))
.Returns(data);
_mockTransactionFactory.Setup(x => x.Create()).Returns(_mockTransaction.Object);
_mockTransaction.Setup(x => x.Commit());
_mockTransaction.Setup(x => x.Dispose());
var dto = new CompanyDto {ObjectId = 1, Name = "Company1"};
var result = _companyApplication.AddCompany(dto);
_mockCompanyService.Verify(t => t.Add(It.IsAny<Company>()));
}
Those two tests pass just fine. However, I'm having trouble coming up with a test for AddCompanyContact, because it calls FindByIdJoin as part of its flow, and that seems to be getting in the way.
Specifically, is there a way to mock var contactCompanies = FindByIdJoin<Company, CompanyDto>(companyContactDto.CompanySK) in a test for the AddCompanyContact method?
Thanks!
There is two alternatives that i see depending on the amount of work that you want to do.
Wrap that call into a object and instantiate it using a IOC container. This is the one that i feel would take the most effort if you are not using one already.
Turn that call into a Func and make a method without that parameter that does the call. This approach has the disadvantage that the top call will be untestable but will allow access to the rest of the method.
Example Below:
public ResultSet<CompanyContactDto> AddCompanyContact(CompanyContactDto companyContactDto)
{
AddCompanyContact(CompanyContactDto, ()=>
{
return FindByIdJoin<Company, CompanyDto> companyContactDto.CompanySK);
}
}
public ResultSet<CompanyContactDto> AddCompanyContact(CompanyContactDto companyContactDto, Func<WhateverTheMethodReturns> findIdReplacement)
{
var result = new CompanyContactDto();
var company = new Company();
var contact = new CompanyContact();
Mapper.Map(companyContactDto, contact);
using (ITransaction t = _transactionFactory.Create())
{
var contactCompanies = findIdReplacement();
Mapper.Map(contactCompanies.Data.First(), company);
company.CompanyContacts.Add(contact);
company = _companyService.Update(company);
t.Commit();
}
Mapper.Map(contact, result);
return new ResultSet<CompanyContactDto>(1, new[] { result });
}
I was over complicating the problem... since AddCompanyContact calls FindByIdJoin, all I needed to do was mock the same interface that is used in FindByIdJoin.
Lesson learned: mock interfaces, not classes.

Categories

Resources