如何进行单元测试以测试检查请求标头的方法?

时间:2012-02-13 15:49:12

标签: c# asp.net-mvc unit-testing nunit moq

我对单元测试非常非常新,并且正在尝试为一个非常简单的方法编写测试:

public class myClass : RequireHttpsAttribute
{
    public override void OnAuthorization(AuthoizationContext filterContext)
    {
        var request = filterContext.HttpContext.Request;
        var header = Convert.ToBoolean(request.Headers["Special-Header-Name"]);

        if (!(header || request.IsSecureConnection))
        {
            HandleNonHttpsRequest(filterContext);
        }
    }
}

此方法继承自RequireHttpsAttribute,检查页面是否存在某个标头,如果它丢失或为false,并且页面不安全,则会调用HandleNonHttpsRequest,否则它什么都不做。

我们正在使用Moq和Nunit进行测试。我找到了一些资源来帮助用Moq构建一个fakeHttpContext,但说实话,我不确定如何使用它或在我的单元测试中去哪里以确保假的HttpContexts是或不是导致HandleNonHttpsRequest方法呼叫。

我非常感谢您对此问题的任何指导。

3 个答案:

答案 0 :(得分:20)

// arrange
var context = new Mock<HttpContextBase>();
var request = new Mock<HttpRequestBase>();
var headers = new NameValueCollection
{
    { "Special-Header-Name", "false" }
};
request.Setup(x => x.Headers).Returns(headers);
request.Setup(x => x.HttpMethod).Returns("GET");
request.Setup(x => x.Url).Returns(new Uri("http://www.example.com"));
request.Setup(x => x.RawUrl).Returns("/home/index");
context.Setup(x => x.Request).Returns(request.Object);
var controller = new Mock<ControllerBase>();

var actionDescriptor = new Mock<ActionDescriptor>();
var controllerContext = new ControllerContext(context.Object, new RouteData(), controller.Object);
var filterContext = new AuthorizationContext(controllerContext, actionDescriptor.Object);
var sut = new myClass();

// act
sut.OnAuthorization(filterContext);

// assert
Assert.IsInstanceOfType(filterContext.Result, typeof(RedirectResult));
var redirectResult = (RedirectResult)filterContext.Result;
Assert.AreEqual("https://www.example.com/home/index", redirectResult.Url);

答案 1 :(得分:1)

是的,我会使用Moq并创建一个Mock<AuthorizationContext>。您需要一系列模拟对象来设置虚假请求,最明显的是指定伪标题的NameValueCollection。

var request = new Mock<HttpRequestBase>();
request.SetupGet(c => c.Headers).Return(new NameValueCollection{ /* initialize values here */});
request.SetupGet(c => c.IsSecureConnection).Return(/*specify true or false depending on your test */);

var httpContext = new Mock<HttpContextBase>();
httpContext.SetupGet(c => c.Request).Return(request.Object);


var filterContext = new Mock<AuthorizationContext>();
filterContext.SetupGet(c => c.HttpContext).Return(httpContext.Object);

var myclass = new myClass();
myClass.OnAuthorization(filterContext.Object);

(对不起,如果语法或用法稍微偏离;从头到尾这样做)

您可能需要进入并模拟HandleNonHttpsRequest调用的filterContext上的任何其他成员。关于这个问题我有两个建议,因为如果你正在测试的方法在filterContext上做了很多复杂的事情,它有时会很麻烦:1)直观地检查,如果它足够直接,那么模拟所有被调用的部分2)创建myClass.OnAuthorizationRequest,但除了调用HandleNonHttpsRequest之外,不要实现任何代码。继续运行测试并修复丢失/错误模拟的成员,直到测试通过。然后实现OnAuthorizationRequest的实际逻辑,测试和修复(冲洗重复)直到它通过。

答案 2 :(得分:0)

我在使用ASP.NET MVC 4时遇到了the accepted solution的问题。要解决它,我模拟了http上下文Items属性,否则sut.OnAuthorization导致对象是未定义的异常:

MockHttpContext.Setup(x => x.Items)
    .Returns(new System.Collections.Generic.Dictionary<object, object>());