如何在使用automapper时对单元测试控制器进行单元化?

时间:2012-07-19 02:22:21

标签: asp.net-mvc-3 unit-testing nunit automapper

这是我的控制器

    [POST("signup")]
    public virtual ActionResult Signup(UserRegisterViewModel user)
    {
        if (ModelState.IsValid)
        {
            var newUser = Mapper.Map<UserRegisterViewModel, User>(user);
            var confirmation = _userService.AddUser(newUser);

            if (confirmation.WasSuccessful)
                return RedirectToAction(MVC.Home.Index());
            else
                ModelState.AddModelError("Email", confirmation.Message);

        }
        return View(user);
    }

这是我的单元测试:

    [Test]
    public void Signup_Action_When_The_User_Model_Is_Valid_Returns_RedirectToRouteResult()
    {
        // Arrange
        const string expectedRouteName = "~/Views/Home/Index.cshtml";

        var registeredUser = new UserRegisterViewModel { Email = "newuser@test.com", Password = "123456789".Hash()};
        var confirmation = new ActionConfirmation<User>
                               {
                                   WasSuccessful = true,
                                   Message = "",
                                   Value = new User()
                               };
        _userService.Setup(r => r.AddUser(new User())).Returns(confirmation);

        _accountController = new AccountController(_userService.Object);

        // Act
        var result = _accountController.Signup(registeredUser) as RedirectToRouteResult;


        // Assert

        Assert.IsNotNull(result, "Should have returned a RedirectToRouteResult");
        Assert.AreEqual(expectedRouteName, result.RouteName, "Route name should be {0}", expectedRouteName);
    }

单元测试失败了。

        var result = _accountController.Signup(registeredUser) as RedirectToRouteResult;

当我调试单元测试时,出现以下错误消息:“缺少类型映射配置或不支持的映射。”

我认为这是因为配置是在web项目中,而不是单元测试项目。我该怎么做才能解决它?

3 个答案:

答案 0 :(得分:3)

您需要配置映射器,因此在测试类设置中,而不是按测试设置,调用代码来设置映射。注意,您可能还需要修改您对用户服务调用的期望,因为参数不匹配,即它们是不同的对象。可能你想要一个测试来检查对象的属性是否与传递给方法的模型的属性相匹配。

答案 1 :(得分:2)

您应该使用映射引擎的接口,以便您可以模拟它而不是使用AutoMapper,否则它是集成测试而不是单元测试。

AutoMapper有一个名为IMappingEngine的接口,您可以使用下面的IoC容器将其注入控制器(此示例使用的是StructureMap)。

class MyRegistry : Registry
{
    public MyRegistry()
    {
        For<IMyRepository>().Use<MyRepository>();
        For<ILogger>().Use<Logger>();

        Mapper.AddProfile(new AutoMapperProfile());
        For<IMappingEngine>().Use(() => Mapper.Engine);
    }
}

然后,您将能够使用依赖注入将AutoMapper的映射引擎注入您的控制器,允许您引用您的映射,如下所示:

[POST("signup")]
public virtual ActionResult Signup(UserRegisterViewModel user)
{
    if (ModelState.IsValid)
    {
        var newUser = this.mappingEngine.Map<UserRegisterViewModel, User>(user);
        var confirmation = _userService.AddUser(newUser);

        if (confirmation.WasSuccessful)
            return RedirectToAction(MVC.Home.Index());
        else
            ModelState.AddModelError("Email", confirmation.Message);

    }
    return View(user);
}

您可以在此处详细了解:How to inject AutoMapper IMappingEngine with StructureMap

答案 2 :(得分:0)

将映射抽象为MappingEngine可能很酷。

有时我会使用以下IOC Automapper方法

在IOC建设者中:

  builder.RegisterInstance(AutoMapperConfiguration.GetAutoMapper()).As<IMapper>();

GetAutoMapper在哪里:

 public class AutoMapperConfiguration
    {
        public static IMapper GetAutoMapper()
        {
            var config = new MapperConfiguration(cfg =>
            {
                cfg.AddProfile<OrderModelMapperProfile>();
                cfg.AddProfile<OtherModelMapperProfile>();
                //etc;
               });
            var mapper = config.CreateMapper();
            return mapper;
        }
    }

最后在Controller ctor

 public MyController(IMapper mapper)
        {
            _mapper = mapper;
        }