Mohsen Esmailpour
Mohsen Esmailpour

Reputation: 11544

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> _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. enter image description here enter image description here

Upvotes: 9

Views: 12505

Answers (4)

Aniket Upadhye
Aniket Upadhye

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

Nkosi
Nkosi

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

Henry Been
Henry Been

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

AggieEric
AggieEric

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

Related Questions