Asp.net-Mvc

使用 AutoMapper 對控制器進行單元測試

  • December 18, 2013

我正在嘗試對使用 AutoMapping 的 UpdateUser 控制器進行單元測試。這是控制器的程式碼

更新使用者控制器

   private readonly IUnitOfWork _unitOfWork;
   private readonly IWebSecurity _webSecurity;
   private readonly IOAuthWebSecurity _oAuthWebSecurity;
   private readonly IMapper _mapper;

   public AccountController()
   {
       _unitOfWork = new UnitOfWork();
       _webSecurity = new WebSecurityWrapper();
       _oAuthWebSecurity = new OAuthWebSecurityWrapper();
       _mapper = new MapperWrapper();
   }

   public AccountController(IUnitOfWork unitOfWork, IWebSecurity webSecurity, IOAuthWebSecurity oAuthWebSecurity, IMapper mapper)
   {
       _unitOfWork = unitOfWork;
       _webSecurity = webSecurity;
       _oAuthWebSecurity = oAuthWebSecurity;
       _mapper = mapper;
   }

   //
   // Post: /Account/UpdateUser
   [HttpPost]
   [ValidateAntiForgeryToken]
   public ActionResult UpdateUser(UpdateUserModel model)
   {
       if (ModelState.IsValid)
       {
           // Attempt to register the user
           try
           {
               var userToUpdate = _unitOfWork.UserRepository.GetByID(_webSecurity.CurrentUserId);
               var mappedModel = _mapper.Map(model, userToUpdate);

**mappedModel will return null when run in test but fine otherwise (e.g. debug)**


               _unitOfWork.UserRepository.Update(mappedModel);
               _unitOfWork.Save();

               return RedirectToAction("Index", "Home");
           }
           catch (MembershipCreateUserException e)
           {
               ModelState.AddModelError("", ErrorCodeToString(e.StatusCode));
           }
       }
       return View(model);
   }

這是我的單元測試 UpdateUserControllerTest

[Fact]
   public void UserRepository_Update_User_Success()
   {
       Controller = new AccountController(UnitOfWork, WebSecurity.Object, OAuthWebSecurity.Object, Mapper);
       const string emailAsUserName = "user@username.com";
       const string password = "password";
       const string email = "email@email.com";
       const string emailNew = "newEmail@email.com";
       const string firstName = "first name";
       const string firstNameNew = "new first name";
       const string lastName = "last name";
       const string lastNameNew = "new last name";

       var updatedUser = new User
           {
               Email = emailNew,
               FirstName = firstNameNew,
               LastName = lastNameNew,
               UserName = emailAsUserName
           };

       WebSecurity.Setup(
           s =>
           s.CreateUserAndAccount(emailAsUserName, password,
                                  new { FirstName = firstName, LastName = lastName, Email = email }, false))
                  .Returns(emailAsUserName);
       updatedUser.UserId = WebSecurity.Object.CurrentUserId;

       UnitOfWork.UserRepository.Update(updatedUser);
       UnitOfWork.Save();

       var actualUser = UnitOfWork.UserRepository.GetByID(updatedUser.UserId);
       Assert.Equal(updatedUser, actualUser);

       var model = new UpdateUserModel
           {
               Email = emailAsUserName,
               ConfirmEmail = emailAsUserName,
               FirstName = firstName,
               LastName = lastName
           };
       var result = Controller.UpdateUser(model) as RedirectToRouteResult;
       Assert.NotNull(result);
   }

我有一種直覺,當在測試模式下執行時,映射器不會查看我在 Global.asax 中設置的映射器配置。由於該錯誤僅在執行單元測試期間發生,而不是在按原樣執行網站時發生。我創建了一個 IMappaer 介面作為 DI,因此我可以模擬它以進行測試。我使用 Moq for Mocking 和 xUnit 作為測試框架,我還安裝了尚未使用的 AutoMoq。任何想法?謝謝你看我的長文。希望有人可以提供幫助,一直在撓頭幾個小時並閱讀了很多文章。

在您的測試中,您需要創建IMapper介面的模擬版本,否則您不是單元測試,而是集成測試。然後你只需要做一個簡單的mockMapper.Setup(m => m.Map(something, somethingElse)).Returns(anotherThing).

如果你想在測試中使用真正的 AutoMapper 實現,那麼你需要先設置它。您的測試不會自動獲取您的Global.asax,您還必須在測試中設置映射。當我像這樣進行集成測試時,我通常有一個AutoMapperConfiguration.Configure()在測試夾具設置中呼叫的靜態方法。對於 NUnit,這是[TestFixtureSetUp]方法,我認為對於 xUnit,您只需將其放在建構子中即可。

引用自:https://stackoverflow.com/questions/16446130