Reputation: 21
I am using .net with xUnit and NSubstitute. I want to unit test mapping from UnitPostVModel to UnitBLLModel. When using UnitImgUrlResolver I get an error where it says that Cannot dynamically create an instance of type 'APMAPI.ServicesBLL.Resolvers.UnitImgUrlResolver'. Reason: No parameterless constructor defined.
public class AutoMapperProfile : Profile
{
public AutoMapperProfile()
{
CreateMap<UnitPostVModel, UnitBLLModel> ()
.ForMember(dest => dest.imgUrl, opt => opt.MapFrom<UnitImgUrlResolver>());
}
}
This is my Resolver:
public class UnitImgUrlResolver : IValueResolver<UnitPostVModel, UnitBLLModel, string>
{
IAzureBlobStorageService _azureBlobStorageService;
public UnitImgUrlResolver(IAzureBlobStorageService azureBlobStorageService)
{
_azureBlobStorageService = azureBlobStorageService;
}
public string Resolve(
UnitPostVModel src,
UnitBLLModel destination,
string destMember,
ResolutionContext context)
{
if(src.image == null)
return string.Empty;
var imageName = GenerateRandomAlphaNumeric(10);
var url = _azureBlobStorageService.UploadImageToBlobStorage(src.image, imageName);
return url;
}
}
This is my test function:
public class AutoMapperTests
{
private readonly IMapper _mapper;
public AutoMapperTests()
{
var config = new MapperConfiguration(cfg => {
cfg.AddProfile<AutoMapperProfile>();
});
_mapper = config.CreateMapper();
}
[Fact]
public void Should_Map_UnitPostVModel_To_UnitBLLModel()
{
// Arrange
var unitPostVModel = new UnitPostVModel
{
abbreviation = "A",
name = "Test"
};
// Act
var result = _mapper.Map<UnitBLLModel>(unitPostVModel);
// Assert
Assert.NotNull(result);
Assert.Equal("MockedImageUrl", result.imgUrl);
}
#endregion
}
But I get this error:
Message:
AutoMapper.AutoMapperMappingException : Error mapping types.
Mapping types:
UnitPostVModel -> UnitBLLModel
APMAPI.Models.VModels.UnitPostVModel -> APMAPI.Models.BLLModels.UnitBLLModel
Type Map configuration:
UnitPostVModel -> UnitBLLModel
APMAPI.Models.VModels.UnitPostVModel -> APMAPI.Models.BLLModels.UnitBLLModel
Destination Member:
imgUrl
---- System.MissingMethodException : Cannot dynamically create an instance of type 'APMAPI.ServicesBLL.Resolvers.UnitImgUrlResolver'. Reason: No parameterless constructor defined.
I've tried creating a mock for IAzureBlobStorageService
private readonly IMapper _mapper;
private readonly IAzureBlobStorageService _azureBlobStorageService;
public AutoMapperTests()
{
// Create a mock for IAzureBlobStorageService
_azureBlobStorageService = Substitute.For<IAzureBlobStorageService>();
// Create an instance of UnitImgUrlResolver with the mock
var unitImgUrlResolver = new UnitImgUrlResolver(_azureBlobStorageService);
var config = new MapperConfiguration(cfg => {
// Register the resolver instance
cfg.CreateMap<UnitPostVModel, UnitBLLModel>()
.ForMember(dest => dest.imgUrl, opt => opt.MapFrom(src => unitImgUrlResolver.Resolve(src, null, null, null)));
});
_mapper = config.CreateMapper();
}
[Fact]
public void Should_Map_UnitPostVModel_To_UnitBLLModel()
{
// Arrange
var unitPostVModel = new UnitPostVModel
{
abbreviation = "A",
name = "Test",
description = "Test",
propertyId = Guid.NewGuid(),
type = Guid.NewGuid(),
outOfService = false
};
// Mock the method call to UploadImageToBlobStorage
_azureBlobStorageService.UploadImageToBlobStorage(Arg.Any<IFormFile>(), Arg.Any<string>())
.Returns("MockedImageUrl");
// Act
var result = _mapper.Map<UnitBLLModel>(unitPostVModel);
// Assert
Assert.NotNull(result);
Assert.Equal("MockedImageUrl", result.imgUrl);
}
}
But I still get the same error.
Upvotes: 0
Views: 108
Reputation: 8181
If you are not resolving the mapper from a DI container, you should be able to leverage the custom extension point called ConstructServicesUsing
to override how AutoMapper will instantiate your resolver. This should allow you to mock its implementation:
private readonly IMapper _mapper;
public AutoMapperTests()
{
var config = new MapperConfiguration(cfg => {
cfg.ConstructServicesUsing(type =>
Substitute.For([type], [Substitute.For<IAzureBlobStorageService>()]));
cfg.AddProfile<AutoMapperProfile>();
});
_mapper = config.CreateMapper();
}
With this, we tell AutoMapper to call Substitute.For([type], [Substitute.For<IAzureBlobStorageService>()])
whenever it encounters a custom resolver or converter instance. This should then leverage NSubstitute
to create a mock for that implementation.
Of course, this simple implementation assumes your only custom implementation is that UnitImgUrlResolver
class, but if you have other resolvers and converters being used in the same profile you'd have to change the factory code accordingly to handle each type specifically.
More information on this mechanism here:
Upvotes: 0