Модульное тестирование HttpApplication
У меня есть класс, полученный из HttpApplication, который добавляет некоторые дополнительные функции. Я дошел до того, что мне нужно провести модульное тестирование этих функций, что означает, что я должен иметь возможность создавать новый экземпляр HttpApplication, подделывать запрос и извлекать объект ответа.
Как именно я иду о модульном тестировании объекта HttpApplication? В данный момент я использую Moq, но не знаю, как настроить требуемый макет объекта.
3 ответа
К сожалению, это не особенно легко сделать, так как приложение HttpApplication не очень легко подделывать; нет интерфейса, над которым можно было бы издеваться, и большинство методов не помечены как виртуальные.
Недавно у меня была похожая проблема с HttpRequest и HttpWebResponse. В итоге я решил создать прямую "сквозную" оболочку для методов, которые я хотел использовать:
public class HttpWebRequestWrapper : IHttpWebRequestWrapper
{
private HttpWebRequest httpWebRequest;
public HttpWebRequestWrapper(Uri url)
{
this.httpWebRequest = (HttpWebRequest)HttpWebRequest.Create(url);
}
public Stream GetRequestStream()
{
return this.httpWebRequest.GetRequestStream();
}
public IHttpWebResponseWrapper GetResponse()
{
return new HttpWebResponseWrapper(this.httpWebRequest.GetResponse());
}
public Int64 ContentLength
{
get { return this.httpWebRequest.ContentLength; }
set { this.httpWebRequest.ContentLength = value; }
}
public string Method
{
get { return this.httpWebRequest.Method; }
set { this.httpWebRequest.Method = value; }
}
public string ContentType
{
get { return this.httpWebRequest.ContentType; }
set { this.httpWebRequest.ContentType = value; }
}
}
и т. д.
Это позволило мне посмеяться над моим собственным интерфейсом оболочки. Не обязательно самая изящная вещь в мире, но очень полезный способ макетировать некоторые из менее "насмешливых" частей каркаса.
Прежде чем вы броситесь и сделаете это, тем не менее, стоит проанализировать, что у вас есть, и посмотреть, есть ли лучший подход к вашим тестам, который позволит избежать необходимости оборачивать уроки.
В случае HttpWebRequest, HttpApplication и др., Часто это не IMHO.
Чтобы установить эту оболочку в mock (используя мой пример HttpWebRequest выше), вы затем делаете такие вещи с Moq:
var mockWebRequest = new Mock<IHttpWebRequestWrapper>();
mockWebRequest.SetupSet<string>(c => c.Method = "POST").Verifiable();
mockWebRequest.SetupSet<string>(c => c.ContentType = "application/x-www-form-urlencoded").Verifiable();
mockWebRequest.SetupSet<int>(c => c.ContentLength = 0).Verifiable();
ИМХО добавлять функциональность за счет расширения HttpApplication - не лучшая вещь. HttpContext настолько трудно смоделировать из-за закрытых / внутренних / закрытых классов, что даже если вы успешно пройдете, ваши модульные тесты будут настолько загромождены поддельным кодом, что вы больше не сможете понять, что вы на самом деле тестируете.
Не могли бы вы подробнее рассказать о том, какие функции вы добавляете? Возможно, есть лучший способ добавить эту функцию в ваше приложение.
Ранее я обнаружил следующий блог, в котором объясняется довольно хороший подход с использованием Microsoft Moles.
http://maraboustork.co.uk/index.php/2011/03/mocking-httpwebresponse-with-moles/
Короче говоря, решение предлагает следующее:
[TestMethod]
[HostType("Moles")]
[Description("Tests that the default scraper returns the correct result")]
public void Scrape_KnownUrl_ReturnsExpectedValue()
{
var mockedWebResponse = new MHttpWebResponse();
MHttpWebRequest.AllInstances.GetResponse = (x) =>
{
return mockedWebResponse;
};
mockedWebResponse.StatusCodeGet = () => { return HttpStatusCode.OK; };
mockedWebResponse.ResponseUriGet = () => { return new Uri("http://www.google.co.uk/someRedirect.aspx"); };
mockedWebResponse.ContentTypeGet = () => { return "testHttpResponse"; };
var mockedResponse = "<html> \r\n" +
" <head></head> \r\n" +
" <body> \r\n" +
" <h1>Hello World</h1> \r\n" +
" </body> \r\n" +
"</html>";
var s = new MemoryStream();
var sw = new StreamWriter(s);
sw.Write(mockedResponse);
sw.Flush();
s.Seek(0, SeekOrigin.Begin);
mockedWebResponse.GetResponseStream = () => s;
var scraper = new DefaultScraper();
var retVal = scraper.Scrape("http://www.google.co.uk");
Assert.AreEqual(mockedResponse, retVal.Content, "Should have returned the test html response");
Assert.AreEqual("http://www.google.co.uk/someRedirect.aspx", retVal.FinalUrl, "The finalUrl does not correctly represent the redirection that took place.");
}