如何在 C# 单元测试中将测试 cookie 添加到请求



我如何添加测试 cookie 来请求,以便我可以从单元测试中测试我的代码。考虑这样的代码:

public ActionResult Dashboard()
{
    if (Request.Cookies["usercookie"] == null)
    {
        return RedirectToAction("Index");
    }
    return View();
}

我模拟了所有内容,但我不知道如何向 cookie 添加一些东西,所以这一行Request.Cookies["usercookie"]不返回 null。现在它是空的,并返回我这个错误:

{"对象引用未设置为对象的实例。

这是我的单元测试方法之一:

[TestMethod]
[TestCategory("Unit")]
public void Login_ShouldValidateUserAndLoginSuccessfully()
{
    using (var kernel = new NSubstituteMockingKernel())
    {
        // Setup the dependency incjection
        kernel.Load(new EntityFrameworkTestingNSubstituteModule());
        // Create test request data 
        var request = new LogInRequest { UserName = "test", Password = "test" };
        var fakeResponseHandler = new FakeResponseHandler();
        fakeResponseHandler.AddFakeResponse(new Uri("http://localhost/test"), new HttpResponseMessage(HttpStatusCode.OK));
        ConfigurationManager.AppSettings["SearchApiBaseUrl"] = "http://test/internal";
        var server = new HttpServer(new HttpConfiguration(), fakeResponseHandler);
        var httpClient = new HttpClient(server);
        var fakeCookieManager = new FakeCookieManager();
        var authenticationService = Substitute.For<IAuthenticationService>();
        var newUser = Fake.GetNewUser(1);
        var newUserClaim = Fake.GetNewUserClaim(1, newUser.Id, "http://test/identity/claims/loans");
        authenticationService.GetUserByEmailPasswordAsync(request.UserName, request.Password).Returns(newUser);
        authenticationService.GetUserClaimByEmailAndPasswordAsync(request.UserName, request.Password).Returns(newUserClaim);
        var controller = new HomeController(httpClient, fakeCookieManager, null, authenticationService);
        Fake.SetFakeAuthenticatedControllerContext(controller);
        controller.HttpContext.Session["ReturnUrl"] = "/search"; 
        var result = controller.Login(request);
        Assert.IsNotNull(result);
    }
}

这是 Fake for Httpcontext 中的一个类:

    public static HttpContextBase InitialiseFakeHttpContext(string url = "")
    {
        var HttpContextSub = Substitute.For<HttpContextBase>();
        var RequestSub = Substitute.For<HttpRequestBase>();
        var ResponseSub = Substitute.For<HttpResponseBase>();
        var serverUtilitySub = Substitute.For<HttpServerUtilityBase>();
        var itemsSub = Substitute.For<IDictionary>();
        HttpContextSub.Request.Returns(RequestSub);
        HttpContextSub.Response.Returns(ResponseSub);
        HttpContextSub.Server.Returns(serverUtilitySub);
        var cookie = Substitute.For<HttpResponseBase>();
        HttpContextSub.Response.Returns(cookie);
        return HttpContextSub;
    }

下面是一个示例单元测试,其中在请求上设置了cookie。

使用 NSubstitute 框架来模拟 http 上下文,然后设置请求 cookie 属性。将模拟的 http 上下文应用于控制器上下文以模拟请求。

[TestClass]
public class MyControllerTests {
    [TestMethod]
    public void Request_Cookies_Should_Not_Be_Null() {
        //Arrange
        var cookies = new HttpCookieCollection();
        cookies.Add(new HttpCookie("usercookie"));
        var mockHttpContext = Substitute.For<HttpContextBase>();
        mockHttpContext.Request.Cookies.Returns(cookies);
        var sut = new MyController();
        sut.ControllerContext = new ControllerContext {
            Controller = sut,
            HttpContext = mockHttpContext
        };
        //Act
        var result = sut.Dashboard() as ViewResult;
        //Assert
        Assert.IsNotNull(result);
    }
    public class MyController : Controller {
        public ActionResult Dashboard() {
            if (Request.Cookies["usercookie"] == null) {
                return RedirectToAction("Index");
            }
            return View();
        }
    }
}

更新:

以下是使用手动创建的模拟 HttpContext 的测试的更新版本。

[TestClass]
public class MyControllerTests {
    [TestMethod]
    public void Request_Cookies_Should_Not_Be_Null() {
        //Arrange
        var cookies = new HttpCookieCollection();
        cookies.Add(new HttpCookie("usercookie"));
        var mockHttpContext = new MockHttpContext(cookies);
        var sut = new MyController();
        sut.ControllerContext = new ControllerContext {
            Controller = sut,
            HttpContext = mockHttpContext
        };
        //Act
        var result = sut.Dashboard() as ViewResult;
        //Assert
        Assert.IsNotNull(result);
    }
    public class MyController : Controller {
        public ActionResult Dashboard() {
            if (Request.Cookies["usercookie"] == null) {
                return RedirectToAction("Index");
            }
            return View();
        }
    }

    private class MockHttpContext : HttpContextBase {
        private readonly MockRequest request;
        public MockHttpContext(HttpCookieCollection cookies) {
            this.request = new MockRequest(cookies);
        }
        public override HttpRequestBase Request {
            get {
                return request;
            }
        }
        public class MockRequest : HttpRequestBase {
            private readonly HttpCookieCollection cookies;
            public MockRequest(HttpCookieCollection cookies) {
                this.cookies = cookies;
            }
            public override HttpCookieCollection Cookies {
                get {
                    return cookies;
                }
            }
        }
    }
}

使用最小起订量框架也是如此

用于模拟 HTTP 上下文的模拟上下文类

public class MockContext
{
    public Mock<RequestContext> RoutingRequestContext { get; private set; }
    public Mock<HttpContextBase> Http { get; private set; }
    public Mock<HttpServerUtilityBase> Server { get; private set; }
    public Mock<HttpResponseBase> Response { get; private set; }
    public Mock<HttpRequestBase> Request { get; private set; }
    public Mock<HttpSessionStateBase> Session { get; private set; }
    public Mock<ActionExecutingContext> ActionExecuting { get; private set; }
    public HttpCookieCollection Cookies { get; private set; }
    public MockContext()
    {
        this.RoutingRequestContext  = new Mock<RequestContext>(MockBehavior.Loose);
        this.ActionExecuting        = new Mock<ActionExecutingContext>(MockBehavior.Loose);
        this.Http                   = new Mock<HttpContextBase>(MockBehavior.Loose);
        this.Server                 = new Mock<HttpServerUtilityBase>(MockBehavior.Loose);
        this.Response               = new Mock<HttpResponseBase>(MockBehavior.Loose);
        this.Request                = new Mock<HttpRequestBase>(MockBehavior.Loose);
        this.Session                = new Mock<HttpSessionStateBase>(MockBehavior.Loose);
        this.Cookies                = new HttpCookieCollection();
        this.RoutingRequestContext.SetupGet (c => c.HttpContext).Returns(this.Http.Object);
        this.ActionExecuting.SetupGet       (c => c.HttpContext).Returns(this.Http.Object);
        this.Http.SetupGet                  (c => c.Request).Returns(this.Request.Object);
        this.Http.SetupGet                  (c => c.Response).Returns(this.Response.Object);
        this.Http.SetupGet                  (c => c.Server).Returns(this.Server.Object);
        this.Http.SetupGet                  (c => c.Session).Returns(this.Session.Object);
        this.Request.Setup                  (c => c.Cookies).Returns(Cookies);
    }
}

这是测试用例

public void IndexTest()
    {
        // arrange
        MockContext mockContext = new MockContext();
        #region creating cookie
        HttpCookie cookie = new HttpCookie(Constant.COOKIE_ADMIN_USER_INFO,
                                         Config.DefaultCountryID.ToString());
        cookie.Values.Add(Constant.COOKIE_ADMIN_VALUE_COUNTRY_ID,
                          Config.DefaultCountryID.ToString());
        cookie.Values.Add(Constant.COOKIE_ADMIN_VALUE_LANGUAGE_ID,
                          Config.DefaultLanguageID.ToString());
        mockContext.Cookies.Add(cookie);
        #endregion
        #region Creating controller
        ControllerContext controllerContex = new ControllerContext()
        {
            HttpContext = mockContext.Http.Object
        };
        HomeController controller = new HomeController()
        {
            ControllerContext = controllerContex
        };
        #endregion
        // act
        var output = (ViewResult)controller.Index();
        var result = output.ViewData;
        // assert
        result.ShouldNotBeNull();
    }

最新更新