Модульный тест для метода, который принимает объект HttpResponse в качестве параметра. OutputStream не доступен - PullRequest
8 голосов
/ 31 августа 2009

Я пытаюсь создать модульный тест для метода, который принимает объект HttpResponse в качестве параметра. Какой правильный способ сделать это? Я надеюсь, что вы опытные юнит-тестеры могут мне помочь.

Дополнительная информация: Я попытался создать поддельный объект HttpResponse, передав StringWriter.

StringBuilder sb = new StringBuilder();
StringWriter sw = new StringWriter(sb);
HttpResponse response = new HttpResponse(sw);
RssGenerator.Generate(response, otherParameters);

Сбой теста с сообщением: System.Web.HttpException: OutputStream недоступен, когда используется пользовательский TextWriter. Тестируемый метод является частью библиотеки классов DLL. Он использует OutputStream объекта Response для создания RSSFeed с XMLWriter.

Ответы [ 6 ]

12 голосов
/ 31 августа 2009

Необходимо использовать пространство имен System.Web.Abstractions

В частности, возьмите HttpResponseBase (http://msdn.microsoft.com/en-us/library/system.web.httpresponsebase.aspx) в качестве входного параметра вместо HttpResponse. Затем вы можете смоделировать HttpResponseBase из ваших тестов. Если у вас есть реальный HttpResponse для передачи, используйте HttpResponseWrapper для создания HttpResponse .

3 голосов
/ 31 августа 2009

Чтобы быть действительно единым целым, вы должны смоделировать HttpResponse и все остальное, чтобы только протестировать код ваших методов. Я не знаю никаких утилит для C # mocking, но этот вопрос может помочь .

Затем вы можете сделать что-то вроде этого (например, Java с Mockito):

HttpResponse response = mock(HttpResponse.class);
OutputStream outputStream = mock(OutputStream.class);
when(response.getOutputStream()).thenReturn(outputStream); 

RssGenerator.generate(response, otherParameters);

Конечно, вам, вероятно, нужно настроить макет больше, чем это, но вы получите общее представление.

2 голосов
/ 28 августа 2015

Если вы хотите получить более подробный ответ, вот что я закончил делать в своем проекте:

_mockResponse = new Mock<HttpResponseBase>();
_contentType = string.Empty;
_mockResponse.SetupSet(r => r.ContentType = It.IsAny<string>()).Callback<string>(value => _contentType = value);
_header = new KeyValuePair<string, string>();
_mockResponse.Setup(r => r.AddHeader(It.IsAny<string>(), It.IsAny<string>())).Callback((string name, string value) => _header = new KeyValuePair<string, string>(name, value));
_writer = new StringBuilder();
_mockResponse.Setup(r => r.Write(It.IsAny<string>())).Callback<string>(s => _writer.Append(s));
var data = "This is the string to send as response";

UTIL.SendStringAsHttpResponse(data, _mockResponse.Object);

Assert.That(_contentType, Is.EqualTo("application/CSV"));
Assert.That(_header.Value, Is.EqualTo("attachment; filename=download.csv"));
Assert.That(_writer.ToString(), Is.EqualTo(data));

где SendStringAsHttpResponse определяется как

public static void SendStringAsHttpResponse(string data, HttpResponseBase response)
1 голос
/ 31 августа 2009

Таким образом, проблема с Mocking HttpResponse заключается в том, что он запечатан, поэтому вы не можете расширить его (и большинство фальшивых фреймворков, которые Mock конкретные классы просто перезаписывают виртуальные методы). Microsoft также была достаточно любезна, чтобы не предоставлять интерфейсы для большинства из них ... так что спасибо MS.

По этой причине (помимо прочего) я обычно заканчиваю тем, что пишу свои собственные интерфейсы для всех запечатанных классов MS, а затем пишу реализации-оболочки, которые принимают класс MS в конструкторе и добавляют их как можно скорее в запросе. Затем вы можете создавать макеты интерфейсов и заставлять их делать что угодно.

1 голос
/ 31 августа 2009

Конструктор для HttpResponse не предназначен для вашего использования, он существует только для цикла страниц ASP.NET, поэтому документации по его созданию нет.

Вам необходимонастройте объект HttpResponse так, чтобы он использовал HttpWriter, иначе он не позволит вам получить доступ к базовому потоку.Однако конструктор установил переменную _httpWriter равной null, поэтому вам нужно найти какой-то другой способ установить ее.

Вы можете использовать программу .NET Reflector , чтобы копатьсяв классе HttpResponse и посмотрите, что он делает.

0 голосов
/ 31 августа 2009

Если бы я не смог провести рефакторинг сигнатуры метода (возможно, методу действительно нужно только одно значение из HttpResponse?), Я бы попросил Eclipse сгенерировать пустую реализацию HttpResponse (да, я на Java, но это то же самое идея) - т.е. реализует все методы, возвращающие нуль - и просто заполняет просто те, которые мне нужны в тестируемом методе, и заставляют их возвращать некоторые постоянные значения. (Да, я тоже могу использовать какую-то насмешливую структуру.)

Причина, по которой вы не можете создать свой собственный экземпляр существующей реализации, заключается в том, что он будет сильно привязан к вашему серверу приложений и, вероятно, потребует создания всевозможных других ганков, даже для создания экземпляров.

Если бы оказалось, что мне нужно что-то более сложное, чем простая нулевая версия HttpResponse, я бы посмотрел на НЕ тестирование этого метода напрямую: возможно, тестирование на один или два уровня будет проще и даст мне такой же уровень доверие к коду.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...