Вопрос ...
Каков наилучший способ модульного тестирования строкового ответа и типа содержимого из нескольких методов контроллера?
Использование ...
Каждый метод возвращает ActionResult
, некоторые из которых являются ViewResult
ответами. Я использую ASP.NET MVC 2 RTM и Moq .
В частности ...
Я хочу получить TextWriter
из HttpContext.Response
, чтобы он содержал полный строковый ответ от ActionResult
.
Почему?
1. В рамках модульных тестов
Я хочу проверить некоторые конкретные, если содержимое имеет , а не не существует с выводом.
2. Время выполнения через рабочий поток
Я использую фоновый рабочий поток для обновления статического контента на удаленных серверах, этот контент является выходом из контроллеров и должен быть сгенерирован как таковой. Отправлять запросы на один и тот же сервер через HTTP не рекомендуется, поскольку обновляется множество файлов тысяч.
Я вижу, что один и тот же код используется как в Runtime , так и в Unit Tests , как это будет очень похоже?
Камень преткновения 1
Как правильно настроить макет, чтобы не требовать маршрутов Или вызов RegisterRoutes
и RegisterAllAreas
вызов был успешным, в настоящее время выдается исключение глубоко внутри BuildManagerWrapper::IBuildManager.GetReferencedAssemblies
.
Пример кода
Мои помощники-насмешники выглядят так:
public static HttpContextBase FakeHttpContext()
{
var context = new Mock<HttpContextBase>();
var request = new Mock<HttpRequestBase>();
var response = new Mock<HttpResponseBase>();
var session = new Mock<HttpSessionStateBase>();
var server = new Mock<HttpServerUtilityBase>();
var writer = new StringWriter();
var form = new NameValueCollection();
var queryString = new NameValueCollection();
request.Setup(r => r.Form).Returns(form);
request.Setup(r => r.QueryString).Returns(queryString);
context.Setup(ctx => ctx.Request).Returns(request.Object);
context.Setup(ctx => ctx.Response).Returns(response.Object);
context.Setup(ctx => ctx.Session).Returns(session.Object);
context.Setup(ctx => ctx.Server).Returns(server.Object);
context.Setup(ctx => ctx.Response.Output).Returns(writer);
return context.Object;
}
public static void SetFakeControllerContext(this Controller controller)
{
var httpContext = FakeHttpContext();
var routeData = new RouteData();
var routeData = RouteTable.Routes.GetRouteData(httpContext);
ControllerContext context = new ControllerContext(new RequestContext(httpContext, routeData), controller);
controller.ControllerContext = context;
}
И моя текущая попытка использования TestMethod выглядит следующим образом:
[TestMethod]
public void CodedJavaScriptAction_Should_Return_JavaScript_Response()
{
// Arrange
var controller = new CodedController();
controller.SetFakeControllerContext();
// Act
var result = controller.CodedJavaScript(); // Response is made up as a ViewResult containing JavaScript.
var controllerContext = controller.ControllerContext;
var routeData = controllerContext.RouteData;
routeData.DataTokens.Add("area", "Coded");
routeData.Values.Add("area", "Coded");
routeData.Values.Add("controller", "Coded");
routeData.Values.Add("action", "CodedJavaScript");
var response = controllerContext.HttpContext.Response;
response.Buffer = true;
var vr = result as ViewResult;
vr.MasterName = "CodedJavaScript";
result.ExecuteResult(controllerContext);
// Assert
var s = response.Output.ToString();
Assert.AreEqual("text/javascript", response.ContentType);
Assert.IsTrue(s.Length > 0);
// @todo: Further tests to be added here.
}
Моя область, просмотры и общие файлы:
Areas\Coded\Controllers\CodeController.cs
- Areas\Coded\Views\Coded\CodedJavaScript.aspx
- Areas\Coded\CodedAreaRegistration.cs
- Views\Shared\CodedJavaScript.Master
EDIT : отредактировано и теперь включает в себя как модульное тестирование, так и выполнение во время выполнения. Спасибо @Darin Dimitrov за упоминание Integration Testing , но теперь в этом вопросе также есть элемент времени выполнения.
EDIT : после некоторого тестирования и обзора с использованием некоторого исходного кода MvcIntegrationTestFramework, на который ссылается alexn . При использовании AppDomain.CreateDomain
и SimpleWorkerRequest
для создания нового запроса я обнаружил, что невозможно создать новый запрос с помощью этого метода в процессе, который уже имеет активный запрос, из-за используемых значений static
. Так что это исключает этот метод.
Вероятно, та же проблема, но мне сейчас интересно, можно ли результат из частичного просмотра вернуть в виде строки более напрямую?