Reputation: 11544
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> _productServiceRepository;
private readonly Lazy<IProductPackageRepository> _productPackageRepository;
public ProductServiceService(
Lazy<IProductServiceRepository> productServiceRepository,
Lazy<IProductPackageRepository> productPackageRepository)
{
_productServiceRepository = productServiceRepository;
_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 mockProductServiceRepository = new Mock<Lazy<IProductServiceRepository>>();
var repo = new Mock<IProductPackageRepository>();
repo.Setup(r => r.AnyAsync(It.IsAny<Expression<Func<ProductPackageEntity, bool>>>()));
var mockProductPackageRepository = new Lazy<IProductPackageRepository>(() => repo.Object);
var sut = new ProductServiceService(mockProductServiceRepository.Object, mockProductPackageRepository);
// 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)));
}
mockProductPackageRepository
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.
Upvotes: 9
Views: 12505
Reputation: 1
I have class where I have used mapper with Lazy keyword below is the example where I have added code example.
public class EntityBusinessComponent : BusinessComponent, IEntityBusinessComponent
{
private readonly ITableBusinessComponent tableComponent;
private readonly IEntityDefRepository entityDefRepository;
private readonly Lazy<EntityCustomMapper> entityCustomMapper;
private EntityCustomMapper EntityCustomMapper
{
get { return entityCustomMapper.Value; }
}
public EntityBusinessComponent(ITableBusinessComponent tableComponent,
IEntityDefRepository entityDefRepository,
Lazy<EntityCustomMapper> entityCustomMapper)
{
this.tableComponent = tableComponent;
this.entityDefRepository = entityDefRepository;
this.entityCustomMapper = entityCustomMapper;
}
}
Mapper Used in below method code
private async Task<string> GenerateEntityTypeDefinition(Guid entityId)
{
string entityTypeDefinition = string.Empty;
EntityBase entity = EntityCustomMapper.ToEntityBase(entityDefinitionEo, assemblyName, AssemblyBuilderAccess.RunAndCollect);
if (entity == null)
return entityTypeDefinition;
List<EntityBase> entityList = EntityCustomMapper.ToEntityRelations(entityDefinitionEo, entity);
if (entityList.IsNotNullOrEmpty())
{
//Your Code
}
return entityTypeDefinition;
}
Below is XUnit test case created for Lazy Mapper
Step:1 I'm passing object mapper in constructor of EntityCustomMapper class if you dont have same scenario keep it blank.
var objectMapperMock = new Mock<IObjectMapper>();
var entityMapper = new Mock<EntityCustomMapper>(objectMapperMock.Object);
Step:2 Setup mock which value you want to return
entityMapper.Setup(r => r.ToEntityBase(It.IsAny<EntityDefinitionEO>(), assemblyName, AssemblyBuilderAccess.RunAndCollect)).Returns(entityBase);
Setp:3 Create mock of Lazy class
var entityMapperLazy = new Lazy<EntityCustomMapper>(() => entityMapper.Object);
Step:4 Pass mock object to component
public async Task UpdateTest()
{
EntityThinEO entThin = new();
Guid EntityId = new Guid("xxxxx-xxxx-xxxxx-xxxxxx");
var entityRepository = new Mock<IEntityDefRepository>();
var tableRepository = new Mock<ITableBusinessComponent>();
var objectMapperMock = new Mock<IObjectMapper>();
var entityMapper = new Mock<EntityCustomMapper>(objectMapperMock.Object);
entityRepository.Setup(r => r.FetchThinEO(It.IsAny<Guid>())).ReturnsAsync(entThin);
entityRepository.Setup(r => r.SaveAllAsync(It.IsAny<EntityObject>())).ReturnsAsync(true);
EntityDefinitionEO entityDefinitionEO = new EntityDefinitionEO();
entityRepository.Setup(r => r.GetEntity(It.IsAny<Guid>())).ReturnsAsync(entityDefinitionEO);
entityMapper.Setup(r => r.ToEntityRelations(It.IsAny<EntityDefinitionEO>(), It.IsAny<EntityBase>())).Returns(entityList);
var entityMapperLazy = new Lazy<EntityCustomMapper>(() => entityMapper.Object);
objectMapperMock.Setup(x => x.Map(It.IsAny<EntityThinEO>(), It.IsAny<EntityThinEO>())).Returns(entThin);
var entityBusinessComponent = new EntityBusinessComponent(tableRepository.Object, entityRepository.Object, entityMapperLazy);
entityBusinessComponent.ObjectMapper = objectMapperMock.Object;
bool result = await entityBusinessComponent.UpdateTypeDefination(EntityId);
Assert.True(result);
}
Upvotes: 0
Reputation: 247018
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();
}
}
}
Upvotes: 23
Reputation: 381
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>();
Upvotes: 0
Reputation: 1209
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.
Upvotes: 2