15

我正在尝试对使用 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。任何想法?谢谢你看我的长文。希望有人可以提供帮助,一直在挠头几个小时并阅读了很多帖子。

4

1 回答 1

19

在您的测试中,您需要创建IMapper接口的模拟版本,否则您不是单元测试,而是集成测试。然后你只需要做一个简单的mockMapper.Setup(m => m.Map(something, somethingElse)).Returns(anotherThing).

如果你想在测试中使用真正的 AutoMapper 实现,那么你需要先设置它。您的测试不会自动获取您的Global.asax,您还必须在测试中设置映射。当我像这样进行集成测试时,我通常有一个AutoMapperConfiguration.Configure()在测试夹具设置中调用的静态方法。对于 NUnit,这是[TestFixtureSetUp]方法,我认为对于 xUnit,您只需将其放在构造函数中即可。

于 2013-05-09T18:28:52.480 回答