2010-11-01 5 views
5

Я использую Moq для создания Mock<HttpResponseBase> для тестирования FileResult Я создаю для своего приложения MVC2.HttpResponseBase.Headers пусты при запуске теста

В WriteFile(HttpResponseBase response) способе FileResult, у меня есть следующий код в конце:

// Write the final output with specific encoding. 
response.OutputStream.Write(output, 0, output.Length); 
response.AppendHeader("Content-Encoding", encoding); 

Он будет использовать utf-8 или gzip в зависимости от кодировки от Accept-Encoding заголовка запроса.

Итак, в моем тесте, я настроить мой Mock<HttpResponseBase> так:

var mockResponse = new Mock<HttpResponseBase>(); 
mockResponse.Setup(r => r.OutputStream).Returns(new MemoryStream()); 
mockResponse.Setup(r => r.Headers).Returns(new NameValueCollection()); 

Но когда я на самом деле проверить, что заголовок был установлен, Content-Encodingвсегда возвращает нулевое значение:

var response = mockResponse.Object; 
Assert.AreEqual("utf-8", response.Headers["Content-Encoding"]); 

Странно то, что OutputStream получает данные, записанные на него, и могу утверждать, что он пишет правильное значение.

Странно, что когда я действительно отлаживаю FileResult в веб-проекте, заголовок отправляется правильно.

У кого-нибудь есть понимание? При необходимости я могу предоставить больше кода.

+0

Можете ли вы добавить больше кода относительно установки Moq. – Ahmad

ответ

4

Я кончался только насмешливый метод AppendHeader насильно добавить заголовок к HttpResponseBase " ы заголовки:

mockResponse 
    .Setup(r => r.AppendHeader(It.IsAny<string>(), It.IsAny<string>())) 
    .Callback((string k, string v) => mockResponse.Object.Headers.Add(k, v)); 

Я подозреваю, что есть что-то дальше вниз внутри вызова AppendHeader что не любит добавлять заголовки без фактического HttpResponseBase на месте.

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

2

на основе кода установки при условии (не уверен, если его опечатка), я думаю, что следует читать следующим образом

var Response = new Mock<HttpResponseBase>(); 
Response.Setup(r => r.OutputStream).Returns(new MemoryStream()); 
Response.Setup(r => r.Headers).Returns(new NameValueCollection()); 
+0

Да, это была опечатка в сообщении. Я назвал это по-другому в коде в сообщении, чем фактический код, который я использовал. В «реальном» коде это свойство называется «Response» класса «MockHttpContext», который я создал. Вышеприведенный код - это * только * часть, которая модифицирует 'Mock '. – TheCloudlessSky

+0

@TheCloudlessSky - мой ответ спорный, тогда – Ahmad

+0

Это сработало. Интересно, как вы должны использовать «MemoryStream» для настройки заголовков. Пробовал сто других вещей до этого. Спасибо, @Ahmad. – Alex

4

Проблема, с которой вы сталкиваетесь, связана с тем, что вы пытаетесь частично издеваться над классом HttpResponseBase. Запись в выходной поток работает, потому что свойство (OutputStream в этом случае) издевается и получает доступ с SUT (System Under Test).

Однако, когда вы издеваетесь о собственности Headers, это только то свойство, которое насмехается, а не AppendHeader, что и делает ваш SUT на самом деле. По умолчанию mocks, созданный Moq, просто заглушает все методы и свойства как возвращающие значения по умолчанию, поэтому AppendHeader фактически ничего не делает.

Существует два решения этого вопроса: первое - это чисто тестирование на взаимодействие и мой предпочтительный подход. Не макет Headers, но вместо этого проверьте AppendHeader.

Mock<HttpResponseBase> responseMock = new Mock<HttpResponseBase>(); 
//the rest of response setup 
FileResult sut = new MyFileResult(); 
sut.WriteFile(responseMock.Object); 
responseMock.Verify(response=>response.AppendHeader("Content-Encoding", "utf8")); 

Второй подход состоит в использовании частичного насмешливых MOq, которая сделала бы реальные методы класса фиктивного объекта вызова, если они не были установлены в явном виде.

Mock<HttpResponseBase> responseMock = new Mock<HttpResponseBase>(){ CallBase = true }; 
//the rest of response setup 
FileResult sut = new MyFileResult(); 
sut.WriteFile(responseMock.Object); 
Assert.AreEqual("utf-8", responseMock.Object.Headers["Content-Encoding"]); 

Я бы предпочел первую версию с небольшим отрывом, поскольку вы проверяете свое взаимодействие с каркасом. Вторая версия - это скорее государственный тест, так что теоретически вам даже не нужен макет, вы можете просто использовать фактический класс. Однако в случае HttpResponseBase это почти разумно, так как его конструктор защищен, поэтому, создавая макет, вы в основном извлекаете из него встроенный, без необходимости вручную писать тестовый двойной файл.

+0

Да, я не понимал, что Мок укусил «AppendHeader». Установка 'CallBase = true' показывает это. Мне нравится ваша идея проверить, что он * сделал * установить заголовок, но он не * действительно * убедитесь, что заголовок установлен с конечным состоянием, которое отправляется (как вы сказали). Я мог случайно вызвать другой «AppendHeader», а затем перезаписать его другим вызовом (хотя, я думаю, я мог бы также проверить это). Спасибо за ваши мысли! – TheCloudlessSky

+0

WriteFile - это защищенный член, как вы можете его называть напрямую. –

Смежные вопросы