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