AutoMapper和AutoFixture中的冲突

时间:2017-08-01 11:53:24

标签: automapper autofixture

我有2个类,Class1应该映射到Class2。我使用 AutoMapper 进行映射。我想测试我的映射器配置,为此我使用 AutoFixture 。源类Class1具有IList<>类型的属性,目标类Class2具有类似的属性,但类型为IEnumerable<&gt ;.为了简化测试准备,我使用 AutoFixture (使用 AutoMoqCustomization )初始化源和目标对象。但在初始化IEnumerable<>类型的属性之后使用AutoFixture,AutoMapper无法映射属性。

错误文字:

映射类型时出错。

  

映射类型:Class1 - > Class2 ConsoleApplication1.Class1 - >   ConsoleApplication1.Class2

     

类型地图配置:Class1 - > Class2 ConsoleApplication1.Class1 - >   ConsoleApplication1.Class2

     

属性:项目

有人可以帮我配置AutoMapper或AutoFixture来使映射工作吗?作为一种解决方法,我可以将null分配给目标属性,但我不想在每个测试中执行此操作。

简化的代码示例:

public class AutoMapperTests
{
    public static void TestCollectionsProperty()
    {
        Mapper.Initialize(cfg =>
        {
            cfg.CreateMap<ItemClass1, ItemClass2>();
            cfg.CreateMap<Class1, Class2>();
        });

        var src = new Class1();
        src.Items = new List<ItemClass1>()
        {
            new ItemClass1() { Text = "111" },
            new ItemClass1() { Text = "222" }
        };

        var fixture = new Fixture();
        var dst = fixture.Create<Class2>();

        Mapper.Map(src, dst); //Error at this line of code
    }
}

public class Class1
{
    public IList<ItemClass1> Items { get; set; }
}

public class Class2
{
    public IEnumerable<ItemClass2> Items { get; set; }
}

public class ItemClass1
{
    public string Text { get; set; }
}
public class ItemClass2
{
    public string Text { get; set; }
}

3 个答案:

答案 0 :(得分:1)

这本身并不是一个AutoFixture问题。您可以在没有自动混合的情况下重现它,而不是像这样创建dst

var dst = new Class2();
dst.Items = Enumerable.Range(0, 1).Select(_ => new ItemClass2());

这将产生类似的错误消息:

  

无法转换类型为'WhereSelectEnumerableIterator 2[System.Int32,Ploeh.StackOverflow.Q45437098.ItemClass2]' to type 'System.Collections.Generic.IList的对象1 [Ploeh.StackOverflow.Q45437098.ItemClass2]'

这应该是不言自明的:WhereSelectEnumerableIterator<int, ItemClass2>没有实现IList<ItemClass2>。 AutoMapper尝试进行转换,但失败了。

最简单的解决方法可能是避免填充dst

var dst = new Class2();

如果你必须使用AutoFixture,你可以这样做:

var dst = fixture.Build<Class2>().OmitAutoProperties().Create();

然而,除非Class2构造函数做了一些复杂的事情,否则在这种情况下我没有看到使用AutoFixture的重点。

另一方面,如果您需要填充dst,则只需确保dst.Items可转换为IList<ItemClass2>。一种方法是这样的:

var dst = fixture.Create<Class2>();
dst.Items = dst.Items.ToList();

您可以创建自定义以确保自动生成,但如果您需要帮助,请提出一个新问题(如果您找不到已回答该问题的问题)。

答案 1 :(得分:0)

以下是您的问题的工作示例。正如@Mark Seemann所说,Mapper.CreateMap已被弃用,因此这个例子正在使用新结构。

Mapper.Initialize(cfg =>
{
    cfg.CreateMap<ItemClass1, ItemClass2>();
    cfg.CreateMap<Class1, Class2>();
});

var src = new Class1();
src.Items = new List<ItemClass1>()
{
    new ItemClass1() { Text = "111" },
    new ItemClass1() { Text = "222" }
};

var dest = Mapper.Map<Class1, Class2>(src);

答案 2 :(得分:0)

AM需要IList,因为您要映射到现有列表,并通过调用IList.Add来工作。