Mock HttpContext для модульного тестирования контроллера MVC ядра .NET?

103

У меня есть функция в контроллере, который я тестирую, и ожидает значений в заголовке HTTP-запроса. Я не могу инициализировать HttpContext, потому что он доступен только для чтения.

Моя функция контроллера ожидает значение заголовка HTTP-запроса для "идентификатора устройства"

[TestMethod]
public void TestValuesController()
{
    ValuesController controller = new ValuesController();

    //not valid controller.HttpContext is readonly
    //controller.HttpContext = new DefaultHttpContext(); 

    var result = controller.Get();
    Assert.AreEqual(result.Count(), 2);
}

Есть ли простой способ сделать это без использования сторонней библиотеки?

Джеймс Вежба
источник
1
Не использовать HttpContext? Весь смысл использования контроллеров в том, что данные поступают через параметры контроллера. Если ваш контроллер использует HttpContext для чтения данных, как если бы это была страница WebForms, у вас есть проблема.
Панайотис Канавос
@PanagiotisKanavos Значение в заголовке - это часть информации, указывающая, с какого мобильного устройства поступает вызов. Это необходимо для получения правильных данных. Идентификатор устройства указан в заголовке, поскольку идентификатор необходим для аутентификации, которая обрабатывается фильтром настраиваемых действий. Я мог бы передать идентификатор устройства в качестве параметра маршрута, но он был бы избыточным,
Джеймс Вежба
Проверьте FromHeaderAttribute, но также проверьте дубликат. HttpContext теперь можно вводить через конфигурацию
Панайотис Канавос
1
Я предлагаю вам отредактировать свой вопрос, указав именно то, что вы хотите (доступ к полям заголовка для идентификации мобильных устройств). Документация по ASP.NET, похоже, переживает ... "переходный" период, мягко говоря, с отсутствующими страницами документации. Отметьте этот почти идентичный вопрос, который спрашивает, как маршрутизировать мобильные устройства
Панайотис Канавос

Ответы:

237

Мне удалось инициализировать httpcontext и заголовок следующим образом:

[TestMethod]
public void TestValuesController()
{
    ValuesController controller = new ValuesController();
    controller.ControllerContext = new ControllerContext();
    controller.ControllerContext.HttpContext = new DefaultHttpContext();
    controller.ControllerContext.HttpContext.Request.Headers["device-id"] = "20317";
    var result = controller.Get();
    //the controller correctly receives the http header key value pair device-id:20317
    ...
}
Джеймс Вежба
источник
20

Вместо того, чтобы издеваться над HTTPContext, вероятно, лучше сопоставить заголовок с параметром метода. Например, в контроллере в нижней части этого ответа idпараметру присваивается значение заголовка с именем, равным «идентификатор устройства» ... Затем модульный тест становится

[TestMethod]
public void TestValuesController()
{
    ValuesController controller = new ValuesController();
    var result = controller.GetHeaderValue("27");
    Assert.AreEqual(result, "27");
}

Хотя вы можете издеваться над HttpContext, на мой взгляд, этого следует избегать, если у вас нет выбора. Документацию для FromHeaderAttribute можно найти здесь FromHeaderAttribute Class .

public class ValuesController: Controller
{
    public string GetHeaderValue([FromHeader(Name = "device-id")] string id)
    {
        return id;
    }
}
GlennSills
источник
1
В моем случае, IIRC, требовалось включить его в заголовок http, потому что то же значение необходимо было оценить в компоненте промежуточного программного обеспечения ядра .net
Джеймс Вьерцба