单元测试automapper

Eth*_*fer 3 c# asp.net-mvc unit-testing automapper

我无法让automapper在我的单元测试中工作.我正在注入映射引擎,这在代码中工作正常,但不在测试中.这是我的测试设置和测试.我正在使用Moq来模拟映射引擎.

private static IDbContext Context { get; set; }
private static Mock<IMappingEngine> Mapper { get; set; }
private static Guid MenuId { get; set; }

private static Guid menuItem1Id { get; set; }
private static Guid menuItem2Id { get; set; }
private static Guid menuItem3Id { get; set; }

[ClassInitialize]
public static void SetUp(TestContext context)
{
    MenuId = Guid.NewGuid();
    Context = new TestDbContext();

    menuItem1Id = Guid.NewGuid();
    menuItem2Id = Guid.NewGuid();
    menuItem3Id = Guid.NewGuid();

    var contentPage1 = new ContentPage { Id = Guid.NewGuid(), ActionName = "ActionName1", ControllerName = "ControllerName1", MenuItemId = menuItem1Id };
    var contentPage2 = new ContentPage { Id = Guid.NewGuid(), ActionName = "ActionName2", ControllerName = "ControllerName2", MenuItemId = menuItem2Id };
    var contentPage3 = new ContentPage { Id = Guid.NewGuid(), ActionName = "ActionName3", ControllerName = "ControllerName3", MenuItemId = menuItem3Id };

    var menuItem1 = new MenuItem { Id = menuItem1Id, MenuId = MenuId, DisplayName = "MenuItem1", ExternalUrl = null, Target = Target._self, Active = true, ContentPage = contentPage1 };
    var menuItem2 = new MenuItem { Id = menuItem1Id, MenuId = MenuId, DisplayName = "MenuItem2", ExternalUrl = null, Target = Target._self, Active = true, ContentPage = contentPage2 };
    var menuItem3 = new MenuItem { Id = menuItem1Id, MenuId = MenuId, DisplayName = "MenuItem3", ExternalUrl = null, Target = Target._self, Active = true, ContentPage = contentPage3 };

    var menu = new Models.Menu { Id = MenuId, Name = "TestMenu", SiteId = Guid.NewGuid(), MenuItems = new List<MenuItem> { menuItem1, menuItem2, menuItem3 } };

    Context.Menus.Add(menu);
    Context.MenuItems.Add(menuItem1);
    Context.MenuItems.Add(menuItem2);
    Context.MenuItems.Add(menuItem3);

    var menuItemQueryResult = new List<MenuItemQueryResult>
    {
        new MenuItemQueryResult { Id = menuItem1Id, DisplayName = "MenuItem1", ExternalUrl = null, Target = Target._self, Active = true, ActionName = "ActionName1", ControllerName = "ControllerName1" },
        new MenuItemQueryResult { Id = menuItem1Id, DisplayName = "MenuItem2", ExternalUrl = null, Target = Target._self, Active = true, ActionName = "ActionName2", ControllerName = "ControllerName2" },
        new MenuItemQueryResult { Id = menuItem1Id, DisplayName = "MenuItem3", ExternalUrl = null, Target = Target._self, Active = true, ActionName = "ActionName3", ControllerName = "ControllerName3" }
    };

    Mapper = new Mock<IMappingEngine>();

    Mapper.Setup(m => m.Map<IEnumerable<MenuItem>, IEnumerable<MenuItemQueryResult>>(It.IsAny<IEnumerable<MenuItem>>()))
                        .Returns(menuItemQueryResult);
}

[TestMethod]
public void Retrieve_RequestMenu_QueryResultReturned()
{
    var handler = new MenuQueryHandler(Context, Mapper.Object);
    var query = new MenuQuery("TestMenu");
    var result = handler.Retrieve(query);
    Assert.IsNotNull(result);
    Assert.IsInstanceOfType(result, typeof(MenuQueryResult));

    var item = result.FirstOrDefault(r => r.Id == menuItem1Id);
    Assert.IsNotNull(item);
}
Run Code Online (Sandbox Code Playgroud)

以下是我正在测试的内容:

public class MenuQueryHandler : IQueryHandler<MenuQuery, MenuQueryResult>
{
    private IDbContext Context { get; set; }
    private IMappingEngine Mapper { get; set; }

    public MenuQueryHandler(IDbContext context, IMappingEngine mapper)
    {
        Context = context;
        Mapper = mapper;
    }

    public MenuQueryResult Retrieve(MenuQuery query)
    {
        Ensure.Argument.Is(query != null);
        Ensure.Argument.IsNot(query.MenuName == string.Empty);

        // Create the view model query result
        var result = new List<MenuItemQueryResult>();

        // Pull the required item from the cont.ext
        var menuItems = Context.MenuItems.Include(m => m.ContentPage).ToList();

        Mapper.Map(menuItems, result);

        return new MenuQueryResult(result);

    }
}
Run Code Online (Sandbox Code Playgroud)

测试运行,但映射永远不会发生.

And*_*ker 6

有几个问题:

  1. 你并没有嘲笑你实际调用的方法.您正在测试的方法调用此方法:

    TDestination Map<TSource, TDestination>(TSource source, TDestination destination);
    
    Run Code Online (Sandbox Code Playgroud)

    这种重载Map采用现有destination对象并映射到其中.

    在你的测试中,你是在模拟重载Map,返回一个新的实例TDestination:

    TDestination Map<TSource, TDestination(TSource source);
    
    Run Code Online (Sandbox Code Playgroud)

    请注意,您正在模拟的那个接受一个参数,而您实际调用的那个参数需要两个参数.

  2. 您的Setup方法在IEnumerable<MenuItem>和之间设置伪映射IEnumerable<MenuItemQueryResult>.在你的测试中,你实际上是Map用a List<MenuItem>和a 调用List<MenuItemQueryResult>.

    在实际使用中,AutoMapper将要处理的List,以List映射您使用的IEnumerable映射.但是,使用模拟方法,您实际上并没有使用您指定的确切类型参数调用该方法.因此,您必须更改Setup呼叫并更改虚假映射.

因此,要解决这些问题,您可以执行以下两项操作之一:

  1. 更改方法以使用Map返回新实例的重载.

    看起来你不需要使用带有两个参数的重载,所以你可以调整方法:

    var result = Mapper.Map<List<MenuItemQueryResult>(menuItems);
    
    Run Code Online (Sandbox Code Playgroud)

    然后在你的测试中:

    Mapper.Setup(m => m.Map<List<MenuItem>, List<MenuItemQueryResult>>(It.IsAny<List<MenuItem>>())
    
    Mapper
        .Setup(m => m.Map<List<MenuItem>, List<MenuItemQueryResult>>(It.IsAny<List<MenuItem>>()))
        .Returns(menuItemQueryResult);
    
    Run Code Online (Sandbox Code Playgroud)
  2. 更改测试以模拟正确的重载Map.

    这有点不太直观,但可能.您必须提供该Map方法的虚假实现:

    Mapper
        .Setup(m => m.Map<List<MenuItem>, List<MenuItemQueryResult>>(It.IsAny<List<MenuItem>>(), It.IsAny<List<MenuItem>>()))
        .Callback((List<MenuItem> menuItems, List<MenuItemQueryResult> queryResults) =>
        {
            queryResults.AddRange(menuItemQueryResult);
        });
    
    Run Code Online (Sandbox Code Playgroud)