Как сделать модульный тест для проверки метода, который проверяет заголовки запросов?
Я очень, очень плохо знаком с модульным тестированием и пытаюсь написать тест для довольно простого метода:
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
проверяет, присутствует ли на странице определенный заголовок, отсутствует ли он или имеет значение "ложь", а также не является ли страница небезопасной, HandleNonHttpsRequest
в противном случае это ничего не делает.
Мы используем Moq и Nunit для тестирования. Я нашел некоторые ресурсы, чтобы помочь создать fakeHttpContext с Moq, но, честно говоря, я не уверен, как его использовать или куда идти в рамках моих модульных тестов, чтобы убедиться, что поддельные HttpContexts являются или не вызывают HandleNonHttpsRequest
метод для вызова.
Я действительно ценю любые рекомендации по этому вопросу.
3 ответа
// 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);
Да, я бы использовал 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);
(извините, если синтаксис или использование немного отключены; делаю это из головы)
Вам может потребоваться войти и смоделировать любые дополнительные члены в filterContext, которые вызывает HandleNonHttpsRequest. У меня есть две рекомендации для этого, так как иногда может возникнуть проблема, если метод, который вы тестируете, делает много сложных вещей в filterContext: 1) проверять визуально и, если это достаточно просто, высмеивать все вызываемые части 2) создайте myClass.OnAuthorizationRequest, но не реализуйте никакого кода, кроме вызова HandleNonHttpsRequest. Продолжайте выполнять тестирование и исправляйте отсутствующие / неправильно проверенные элементы до тех пор, пока тест не пройдет. Затем реализуйте свою фактическую логику для OnAuthorizationRequest, тестируя и исправляя (повтор ополаскивания), пока он не пройдет.
Я столкнулся с проблемой с принятым решением с использованием ASP.NET MVC 4. Чтобы решить его, я издевался над атрибутом элементов контекста http, в противном случае sut.OnAuthorization
Вызывает объект неопределенное исключение:
MockHttpContext.Setup(x => x.Items)
.Returns(new System.Collections.Generic.Dictionary<object, object>());