使用Automapper映射一个视图模型如何,我应该考后? [英] After using Automapper to map a ViewModel how and what should I test?

查看:123
本文介绍了使用Automapper映射一个视图模型如何,我应该考后?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图测试控制器的首页的行动。该操作使用 AutoMapper 映射域客户对象视图模型 TestCustomerForm 。虽然这工作,我担心测试,我从首页行动收到成果的最佳途径。

控制器的索引操作是这样的:

 公众的ActionResult指数()
{
    TestCustomerForm卡斯特= Mapper.Map<客户,
        TestCustomerForm>(_ repository.GetCustomerByLogin(CurrentUserLoginName));    返回查看(卡斯特);
}

和它的 TestMethod的是这样的:

  [TestMethod的]
公共无效IndexShouldReturnCustomerWithMachines()
{
    //安排
    变种顾客= SetupCustomerForRepository(); //得到一个样板客户
    变种的TestController = CreateTestController();    //行为
    结果的ViewResult = testController.Index()作为的ViewResult;    //断言
    Assert.AreEqual(customer.MachineList.Count(),
        (result.ViewData.Model如TestCustomerForm).MachineList.Count());
}

CreateTestController 方法我用 Rhino.Mocks 来模拟一个客户资料库,并将它设置返回从 SetupCustomerForRepository 客户。通过这种方式,我知道,当首页操作调用库将返回目标客户 _repository.GetCustomerByLogin(CurrentUserLoginName) 。因此,我想主张平等的数量足以满足 IndexShouldReturnCustomerWithMachines

所有这一切都表示,我担心以我应该是什么样的测试。


  1. 看来presumptuous铸就 result.ViewData.Model为TestCustomerForm 。这是一个真正的问题?这涉及到我,因为在这种情况下,我没有真正做测试驱动开发,它看起来像我指望一个特定的实现,以满足测试。

  2. 是否有更合适的测试,以确保正确映射?

  3. 我应该测试从 TestCustomerForm
  4. 每个对应的属性
  5. 是我应该做有更广泛的控制器操作测试?


解决方案

这就是为什么我们移动AutoMapper到自定义的ActionResult或ActionFilter的原因之一。在某些时候,你才真正想测试你映射到富FooDto,但不一定是测试实际映射。通过移动AutoMapper到层边界(如控制器的视图之间),你可以只是测试你告诉AutoMapper做什么。

这是类似于测试的ViewResult。你不会从一种观点呈现一个控制器测试,而是你告诉MVC呈现这样的 - 和 - 这样的说法。我们的行动结果变成:

 公共类AutoMapViewResult:的ActionResult
{
    公共类型SourceType中获得{;私人集; }
    公共类型DestinationType {搞定;私人集; }
    公众的ViewResult查看{搞定;私人集; }    公共AutoMapViewResult(类型sourceType的,类型destinationType,视图的ViewResult)
    {
        SourceType中= sourceType的;
        DestinationType = destinationType;
        查看=视图。
    }    公共覆盖无效的ExecuteReuslt(ControllerContext上下文)
    {
        VAR模型= Mapper.Map(View.ViewData.Model,SourceType中,DestinationType);        View.ViewData.Model =模型;        View.ExecuteResult(上下文);
    }
}

在基本控制器类的辅助方法:

 保护AutoMapViewResult AutoMapView< TDestination>(的ViewResult的ViewResult)
{
    返回新AutoMapViewResult(viewResult.ViewData.Model.GetType()的typeof(TDestination)的ViewResult);
}

然后使控制器现在只有指定的内容映射到/从,而不是执行实际映射:<​​/ P>

 公众的ActionResult指数(INT minSessions = 0)
{
    VAR名单从CONF =在_repository.Query()
                其中,conf.SessionCount&GT; = minSessions
                选择CONF;    返回AutoMapView&LT; EventListModel []&GT;(查看(列表));
}

在这一点上,我只需要测试,确保你映射这个Foo对象到此目标FooDto类型,而无需实际执行映射。

编辑:

下面是一个测试片段的例子:

  VAR的ActionResult = controller.Index();actionResult.ShouldBeInstanceOf&LT; AutoMapViewResult&GT;();VAR autoMapViewResult =(AutoMapViewResult)的ActionResult;autoMapViewResult.DestinationType.ShouldEqual(typeof运算(EventListModel []));
autoMapViewResult.View.ViewData.Model.ShouldEqual(QueryResult中);
autoMapViewResult.View.ViewName.ShouldEqual(的String.Empty);

I am attempting to test the Index action of a controller. The action uses AutoMapper to map a domain Customer object to a view model TestCustomerForm. While this works I am concerned about the best way to test the results that I am receiving from the Index action.

The controller's index action looks like this:

public ActionResult Index()
{
    TestCustomerForm cust = Mapper.Map<Customer,
        TestCustomerForm>(_repository.GetCustomerByLogin(CurrentUserLoginName));

    return View(cust);
}

And its TestMethod looks like this:

[TestMethod]
public void IndexShouldReturnCustomerWithMachines()
{
    // arrange
    var customer = SetupCustomerForRepository(); // gets a boiler plate customer
    var testController = CreateTestController();

    // act
    ViewResult result = testController.Index() as ViewResult;

    // assert
    Assert.AreEqual(customer.MachineList.Count(),
        (result.ViewData.Model as TestCustomerForm).MachineList.Count());
}

In the CreateTestController method I use Rhino.Mocks to mock a customer repository and set it up to return the customer from SetupCustomerForRepository. In this manner I know that the repository will return the intended customer when the Index action calls _repository.GetCustomerByLogin(CurrentUserLoginName). Therefore, I figure asserting an equal count is adequate to satisfy IndexShouldReturnCustomerWithMachines.

All of that said I am concerned as to what I should be testing.

  1. It seems presumptuous to cast the result.ViewData.Model as TestCustomerForm. Is this really an issue? This concerns me because in this instance I am not truly doing test driven development and it seems like I am counting on a particular implementation to satisfy the test.
  2. Are there more appropriate tests to ensure correct mapping?
  3. Should I be testing each mapped property from the TestCustomerForm?
  4. Are there more general controller action tests that I should be doing?

解决方案

This is one of the reasons why we move AutoMapper into a custom ActionResult or an ActionFilter. At some point, you only really want to test that you mapped Foo to FooDto, but not necessarily test the actual mapping. By moving AutoMapper into the layer boundaries (such as between controller an view), you can merely test what you're telling AutoMapper to do.

This is similar to testing a ViewResult. You don't test from a controller that a view was rendered, but rather that you told MVC to render such-and-such view. Our action result becomes:

public class AutoMapViewResult : ActionResult
{
    public Type SourceType { get; private set; }
    public Type DestinationType { get; private set; }
    public ViewResult View { get; private set; }

    public AutoMapViewResult(Type sourceType, Type destinationType, ViewResult view)
    {
        SourceType = sourceType;
        DestinationType = destinationType;
        View = view;
    }

    public override void ExecuteResult(ControllerContext context)
    {
        var model = Mapper.Map(View.ViewData.Model, SourceType, DestinationType);

        View.ViewData.Model = model;

        View.ExecuteResult(context);
    }
}

With a helper method on a base controller class:

protected AutoMapViewResult AutoMapView<TDestination>(ViewResult viewResult)
{
    return new AutoMapViewResult(viewResult.ViewData.Model.GetType(), typeof(TDestination), viewResult);
}

Which then makes the controller now only specify what to map to/from, instead of performing the actual mapping:

public ActionResult Index(int minSessions = 0)
{
    var list = from conf in _repository.Query()
                where conf.SessionCount >= minSessions
                select conf;

    return AutoMapView<EventListModel[]>(View(list));
}

At this point, I only need to test, "make sure that you're mapping this Foo object to this destination FooDto type", without needing to actually perform the mapping.

EDIT:

Here's an example of a test snippet:

var actionResult = controller.Index();

actionResult.ShouldBeInstanceOf<AutoMapViewResult>();

var autoMapViewResult = (AutoMapViewResult) actionResult;

autoMapViewResult.DestinationType.ShouldEqual(typeof(EventListModel[]));
autoMapViewResult.View.ViewData.Model.ShouldEqual(queryResult);
autoMapViewResult.View.ViewName.ShouldEqual(string.Empty);

这篇关于使用Automapper映射一个视图模型如何,我应该考后?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆