【问题标题】:how to unit test controller when automapper is used?使用自动映射器时如何对控制器进行单元测试?
【发布时间】:2012-07-19 02:22:21
【问题描述】:

这是我的控制器

    [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 项目中,而不是在单元测试项目中。我该怎么做才能解决它?

【问题讨论】:

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


    【解决方案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

      【讨论】:

      • 我已经使用 AutoMapper 一年了,但我从未意识到 IMappingEngine 的存在。我一直在模拟除了 AutoMapper 之外的所有东西,并且总是想知道为什么我的测试失败了,然后去查看并发现 AutoMapper 没有配置。总是烦人。有界面会好很多:)
      【解决方案3】:

      将映射抽象到 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;
              }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-11-23
        • 2012-04-24
        • 2018-09-19
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-04-26
        • 2012-07-08
        相关资源
        最近更新 更多