abp.io 框架 - 测试
我正在尝试设置一个ApplicationService 类。
我尝试测试的方法使用 'ObjectMapper.Map
我已使用 NSubstitue 作为 LazyServiceProvider,但我无法找到正确的替代品来创建 ObjectMapper。
有人做过吗?
我们解决了问题。
我们使用了 LazyServiceProvider 的替代品。
然后,当 LazyServiceProvider 尝试创建对象映射器时,关键是使用非常具体的设置(请参阅 abp 代码)。
_abpProvider = Substitute.For<IAbpLazyServiceProvider>();
_abpProvider.LazyGetService<IObjectMapper>(Arg.Any<Func<IServiceProvider, object>>()).Returns(_objectMapper);
这允许我们在测试方法中设置自己的 ObjectMapper,并在我们的 ApplicationService 中使用它。
我知道 abp 有一些文档展示了如何在集成测试中模拟
IObjectMapper
,但我正在寻找一种在单元测试中模拟 IObjectMapper
的方法,而不引入任何这些应用程序服务。
目前我还没有找到更好的方法。 ABP 缺乏这方面的文档。
这是我目前拥有的,但我对此不满意:
using Volo.Abp.ObjectMapping;
namespace DL.SomeProject.Database.EFCore.Repositories
{
public class SomeRepository : ISomeRepository
{
private readonly SomeDbContext _dbContext;
private readonly IObjectMapper _objectMapper;
public SomeRepository(SomeDbContext dbContext,
IObjectMapper objectMapper)
{
_dbContext = dbContext;
_objectMapper = objectMapper;
}
public async Task<SomeDomainModel?> GetByIdAsync(Guid someId,
CancellationToken cancellationToken = default)
{
var query = ...;
var entity = await _dbContext.SomeEntities
// We're using Postgres, with some data in JSONB columns
.FromSqlRaw(query)
.AsNoTracking()
.SingleOrDefaultAsync(cancellationToken);
if (entity == null)
{
return null;
}
return _objectMapper.Map<SomeEntity, SomeDomainModel>(entity);
}
}
}
并且
IObjectMapper
只是使用 AutoMapper
实现:
using Volo.Abp.AutoMapper;
using Volo.Abp.Modularity;
namespace DL.SomeProject.Database.EFCore
{
[DependsOn(
...
typeof(AbpAutoMapperModule)
)]
public SomeProjectDatabaseEFCoreModule : AbpModule
{
...
public override void ConfigureServices(ServiceConfigurationContext context)
{
Configure<AbpAutoMapperOptions>(options =>
{
options.AddProfile<DbEntityToDomainModelProfile>(validate: true);
});
context.Services.AddAbpDbContext<SomeDbContext>();
...
}
}
}
using AutoMapper;
using EntityFrameworkCore.Testing.NSubstitute;
using EntityFrameworkCore.Testing.NSubstitute.Extensions;
using FluentAssertions;
using FluentAssertions.Execution;
using NSubstitute;
using Volo.Abp.ObjectMapping;
namespace DL.SomeProject.Database.EFCore.Repositories.Tests
{
public class SomeRepositoryTests
{
public class GetByIdAsync
{
[Fact]
public async Task WhenEntityIsFound_ShouldReturnFoundDomainModel()
{
// Arrange
Guid expectedFoundEntityId = Guid.NewGuid();
var data = new List<SomeEntity>
{
new SomeEntity
{
Id = expectedFoundEntityId,
...
}
};
// Mocking the dbContext
var dbContext = Create.MockedDbContextFor<SomeDbContext>();
dbContext.SomeEntities.AddFromSqlRawResult(data);
// !! Here is the workaround !!
// Create an AutoMapper mapper
var autoMapper = new MapperConfiguration(x =>
x.AddProfile<DbEntityToDomainModelProfile>())
.CreateMapper();
// Mock ABP ObjectMapper Map method to use AutoMapper
var objectMapper = Substitute.For<IObjectMapper>();
objectMapper.Map<SomeEntity, SomeDomainModel>(Arg.Any<SomeEntity>())
.Returns(x
=> autoMapper.Map<SomeEntity, SomeDomainModel>(x.Arg<SomeEntity>()));
var sut = new SomeRepository(dbContext, objectMapper);
// Act
var result = await sut.GetByIdAsync(...);
// Assert
using (new AssertionScope())
{
result.Should().NotBeNull();
result!.Id.Should().Be(expectedFoundRecordId);
}
}
}
}
}