使用Automapper映射一个视图模型如何,我应该考后? [英] After using Automapper to map a ViewModel how and what should I test?
问题描述
我试图测试控制器的首页
的行动。该操作使用 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
。
所有这一切都表示,我担心以我应该是什么样的测试。
- 看来presumptuous铸就
result.ViewData.Model为TestCustomerForm
。这是一个真正的问题?这涉及到我,因为在这种情况下,我没有真正做测试驱动开发,它看起来像我指望一个特定的实现,以满足测试。 - 是否有更合适的测试,以确保正确映射?
- 我应该测试从
TestCustomerForm
? 每个对应的属性 - 是我应该做有更广泛的控制器操作测试?
这就是为什么我们移动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.
- 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. - Are there more appropriate tests to ensure correct mapping?
- Should I be testing each mapped property from the
TestCustomerForm
? - 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屋!