如何模拟对象映射器

问题描述 投票:0回答:2

abp.io 框架 - 测试

我正在尝试设置一个ApplicationService 类。 我尝试测试的方法使用 'ObjectMapper.Map(obj)'

我已使用 NSubstitue 作为 LazyServiceProvider,但我无法找到正确的替代品来创建 ObjectMapper。

有人做过吗?

testing mocking objectmapper abp-framework
2个回答
1
投票

我们解决了问题。

我们使用了 LazyServiceProvider 的替代品。

然后,当 LazyServiceProvider 尝试创建对象映射器时,关键是使用非常具体的设置(请参阅 abp 代码)。

_abpProvider = Substitute.For<IAbpLazyServiceProvider>();
_abpProvider.LazyGetService<IObjectMapper>(Arg.Any<Func<IServiceProvider, object>>()).Returns(_objectMapper);

这允许我们在测试方法中设置自己的 ObjectMapper,并在我们的 ApplicationService 中使用它。


0
投票

我知道 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);
                }
            }
        }
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.