注入和/或模拟Automapper:为什么?

时间:2017-02-14 05:42:39

标签: c# dependency-injection automapper

我正在刷新我对Automapper API的了解。

探索IMapper界面,我发现了一些关于依赖注入和Automapper的帖子,例如: thisthis(它们与.NET Core有关,但在问题的上下文中无关紧要。)

假设,像Automapper这样的映射器的典型用法是:

public class Person
{
    // person properties here
}

public class PersonDto
{
    // person DTO properties here
}

public class SomeApi
{
    // other code here

    public PersonDto FindByName(string name)
    {
        var person = dbContext.People.FirstOrDefault(_ => _.Name == name);

        // mapper is IMapper
        return mapper.Map<PersonDto>(person);
    }
}

为什么我们可能想要注入和/或模仿IMapper

我明白,为什么注入像dbContext这样的东西会很有用 - 在编写单元测试时,你必须以某种方式设置测试环境,以便将测试代码与外界隔离开来。

但是mapper有什么意义呢?

我的意思是,映射是方法逻辑的一部分。这不是一个“外部世界”。这就是为什么编写方法,这是必须测试的内容,但不是嘲笑。

如果我在不使用Automapper的情况下重写FindByName,代码将如下所示:

    public PersonDto FindByName(string name)
    {
        var person = dbContext.People.FirstOrDefault(_ => _.Name == name);

        if (person == null)
            return null;

        return new PersonDto
        {
            Name = person.Name,

            // etc
        };
    }

那么,我们在这里注射/嘲笑什么?作业运营商?真的吗?

看起来依赖注入依赖注入没有任何好处。

我错过了什么吗? 也许,有些情况下,当注入/模拟Automapper真的很有用时(我对在实践中发现的案例感兴趣,而不是理论上的案例)?

2 个答案:

答案 0 :(得分:3)

将此解包为两个问题:

  • 你为什么要注射IMapper?
  • 你为什么要嘲笑IMapper?

对于第一个问题,我会注入IMapper,以防其中一个映射扩展需要依赖。例如,如果您使用的是使用IValueResolver的自定义ITypeConverterDbContext,则需要确保提供了正确的DbContext。如果设置容器以使用工厂方法创建Mapper实例,则扩展使用该工厂方法回调到容器。

如果使用静态Mapper实例,则确保值解析器/类型转换器从容器中获取其依赖关系会更加困难。

对于第二个问题,我不会在任何类型的测试中模仿IMapper。这就像嘲笑JSON.net或StringBuilder一样,没什么意义。

答案 1 :(得分:0)

那就是出于同样的原因:进行单元测试。让我们在您的问题中获取您的代码并修改它并添加一个简单的构造函数作为示例:

public class SomeApi
{
    private IMapper mapper;
    public SomeApi(IMapper mapper)
    {
        this.mapper = mapper;
    }
    // other code here

    public PersonDto FindByName(string name)
    {
        var person = dbContext.People.FirstOrDefault(_ => _.Name == name);

        // mapper is IMapper
        return mapper.Map<PersonDto>(person);
    }
}

如果我想为FindByName编写单元测试怎么办?我想模拟IMapper,因为我希望测试纯粹基于我的模拟而不是AutoMapper。或者,如果我没有决定使用AutoMapper,而是使用任何实现IMapper的类型。或者我可能不希望我的SomeApi类与AutoMapper耦合,或者对AutoMapper有任何依赖。

如果SomeApi类在程序集中,则不需要了解AutoMapper,它应该知道的是IMapper。可以在Composition Root确定IMapper的哪些实施方案。这样,如果使用您的API的人不喜欢AutoMapper,无论出于何种原因,都可以使用他们想要的任何映射器。

在对这个答案的评论中你说:

  

1)当你丢掉方法的最大部分时,你在测试什么?

我正在测试以查看按名称在数据库中查找的代码是否正常工作。

  

2)注入IMapper,您可以从Automapper中获取依赖关系。

不,我不是。如果您的SomeApi类没有耦合到AutoMapper的IMapper,而只是另一个名为IMapper的接口,但是使用的方法或方法相同,那么这就是你要耦合到的

  

3)你有没有看到自定义IMapper实现(我的意思是,在实践中)?

不,我没有。我还没有见过编译器,但它们确实存在。我刚才看到有人写了一篇关于AutoMapper(以及其他mapper&#39; s)性能与手动映射的文章,我可以看到为什么有些人可能想要使用他们自己的映射器。请参阅this

你的问题是为什么要这样做,这些是我能想到的原因。我是在说你应该这样做吗?绝对不。