使用Fakes的Stub和Shim对ASP.NET MVC4进行单元测试

这是一篇导航文,不是翻译。

MSDN对stub和shim的解释和使用场景演示:http://msdn.microsoft.com/en-us/library/hh549175.aspx
一个更详细的示例:http://www.richonsoftware.com/post/2012/04/05/Using-Stubs-and-Shim-to-Test-with-Microsoft-Fakes-in-Visual-Studio-11.aspx

我感兴趣的是如何对mvc项目进行测试:http://www.richonsoftware.com/post/2012/05/02/Noninvasive-Unit-Testing-in-ASPNET-MVC-A-Microsoft-Fakes-Deep-Dive.aspx
里面讲的内容分别有:

1,利用shim来重写第三方类库或系统类库的方法

[TestMethod]
public void TestLogOff()
{
    var accountController = new AccountController();
    var formsAuthenticationSignOutCalled = false;
    RedirectToRouteResult redirectToRouteResult;
 
    //Scope the detours we're creating
    using (ShimsContext.Create())
    {
        //Detours FormsAuthentication.SignOut() to an empty implementation
        ShimFormsAuthentication.SignOut = () =>
        {
            //Set a boolean to identify that we actually got here
            formsAuthenticationSignOutCalled = true;
        };
        redirectToRouteResult = accountController.LogOff() as RedirectToRouteResult;
        Assert.AreEqual(true, formsAuthenticationSignOutCalled);
    }
 
    Assert.NotNull(redirectToRouteResult);
    Assert.AreEqual("Index", redirectToRouteResult.RouteValues["Action"]);
    Assert.AreEqual("Home", redirectToRouteResult.RouteValues["controller"]);
}

2,怎么判断该用stub


[TestMethod]
public void TestLogin()
{
    string testUserName = "TestUserName";
    string testPassword = "TestPassword";
    bool testRememberMe = false;
    string returnUrl = "/foo.html";
 
    var loginModel = new LoginModel
    {
        UserName = testUserName,
        Password = testPassword,
        RememberMe = testRememberMe
    };
 
    var accountController = new AccountController();
 
    //Setup underpinning via stubbing such that UrlHelper 
    //can validate that our "foo.html" is local
    var stubHttpContext = new StubHttpContextBase();
    var stubHttpRequestBase = new StubHttpRequestBase();
    stubHttpContext.RequestGet = () => stubHttpRequestBase;
    var requestContext = new RequestContext(stubHttpContext, new RouteData());
    accountController.Url = new UrlHelper(requestContext);
 
    RedirectResult redirectResult;
    //Scope the detours we're creating
    using (ShimsContext.Create())
    {
        //Sets up a detour for Membership.ValidateUser to our mocked implementation
        ShimMembership.ValidateUserStringString = (userName, password) =>
        {
            Assert.AreEqual(testUserName, userName);
            Assert.AreEqual(testPassword, password);
            return true;
        };
 
        //Sets up a detour for FormsAuthentication.SetAuthCookie to our mocked implementation
        ShimFormsAuthentication.SetAuthCookieStringBoolean = (userName, rememberMe) =>
        {
            Assert.AreEqual(testUserName, userName);
            Assert.AreEqual(testRememberMe, rememberMe);
        };
 
        redirectResult = accountController.Login(loginModel, returnUrl) as RedirectResult;
    }
 
    Assert.NotNull(redirectResult);
    Assert.AreEqual(redirectResult.Url, returnUrl);
}

3,如何还原动态对象


[TestMethod]
public void TestInvalidJsonLogin()
{
    string testUserName = "TestUserName";
    string testPassword = "TestPassword";
    bool testRememberMe = false;
    string testReturnUrl = "TestReturnUrl";
 
    var loginModel = new LoginModel
    {
        UserName = testUserName,
        Password = testPassword,
        RememberMe = testRememberMe
    };
 
    var accountController = new AccountController();
    JsonResult jsonResult;
    //Scope the detours we're creating
    using (ShimsContext.Create())
    {
        //Sets up a detour for Membership.ValidateUser to our mocked implementation
        ShimMembership.ValidateUserStringString = (userName, password) => false;
        jsonResult = accountController.JsonLogin(loginModel, testReturnUrl);
    }
     //答案在这里
    var errors = (IEnumerable<string>)(new PrivateObject(jsonResult.Data, "errors")).Target;
    Assert.AreEqual("The user name or password provided is incorrect.", errors.First());

4,如何给请求添加上下文,及如何在请求中加入用户对象


[TestMethod]
public void TestChangePassword()
{
    string testUserName = "TestUserName";
    string testOldPassword = "TestOldPassword";
    string testNewPassword = "TestNewPassword";
 
    var changePasswordModel = new ChangePasswordModel
    {
        OldPassword = testOldPassword,
        NewPassword = testNewPassword
    };
 
    var accountController = new AccountController();
 
    //Stub HttpContext
    var stubHttpContext = new StubHttpContextBase();
    //Setup ControllerContext so AccountController will use our stubHttpContext
    accountController.ControllerContext = new ControllerContext(stubHttpContext, 
        new RouteData(), accountController);
 
    //Stub IPrincipal
    var principal = new StubIPrincipal();
    principal.IdentityGet = () =>
    {
        var identity = new StubIIdentity { NameGet = () => testUserName };
        return identity;
    };
    stubHttpContext.UserGet = () => principal;
 
    RedirectToRouteResult redirectToRouteResult;
    //Scope the detours we're creating
    using (ShimsContext.Create())
    {
        ShimMembership.GetUserStringBoolean = (identityName, userIsOnline) =>
        {
            Assert.AreEqual(testUserName, identityName);
            Assert.AreEqual(true, userIsOnline);
 
            var memberShipUser = new ShimMembershipUser();
            //Sets up a detour for MemberShipUser.ChangePassword to our mocked implementation
            memberShipUser.ChangePasswordStringString = (oldPassword, newPassword) =>
            {
                Assert.AreEqual(testOldPassword, oldPassword);
                Assert.AreEqual(testNewPassword, newPassword);
                return true;
            };
            return memberShipUser;
        };
 
        var actionResult = accountController.ChangePassword(changePasswordModel);
        Assert.IsInstanceOf(typeof(RedirectToRouteResult), actionResult);
        redirectToRouteResult = actionResult as RedirectToRouteResult;
    }
    Assert.NotNull(redirectToRouteResult);
    Assert.AreEqual("ChangePasswordSuccess", redirectToRouteResult.RouteValues["Action"]);
} 
   
上面种种,文章给的不仅仅是答案,更有思考过程,比如问题原因,可能的解决方法,以及最后给一个最优的方法,值得一读的。

posted @ 2013-10-08 19:23  $walker  阅读(1212)  评论(0编辑  收藏  举报