¿Mock HttpContext para pruebas unitarias de un controlador MVC de .NET core?

95

Tengo una función en un controlador que estoy probando unitariamente que espera valores en el encabezado de la solicitud http. No puedo inicializar HttpContext porque es de solo lectura.

La función de mi controlador espera un valor de encabezado de solicitud http para "id-dispositivo"

[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);
}

¿Existe una forma sencilla de hacer esto sin utilizar una biblioteca de terceros?

James Wierzba
fuente
1
¿No usa HttpContext? El objetivo de usar controladores es que los datos provienen de los parámetros del controlador. Si su controlador usa HttpContext para leer datos como si fuera una página de WebForms, tiene un problema.
Panagiotis Kanavos
@PanagiotisKanavos El valor del encabezado es un dato que indica de qué dispositivo móvil proviene la llamada. Esto es necesario para recuperar los datos correctos. El ID del dispositivo está en el encabezado porque el ID es necesario para la autenticación, que se maneja mediante un filtro de acción personalizado. Podría pasar la ID del dispositivo como parámetro de ruta, pero sería redundante
James Wierzba
Verifique FromHeaderAttribute pero también verifique el duplicado. HttpContext es inyectable a través de la configuración ahora
Panagiotis Kanavos
1
Le sugiero que edite su pregunta para especificar exactamente lo que desea (acceso a los campos de encabezado para identificar dispositivos móviles). La documentación de ASP.NET parece estar pasando por un período de "transición" para decirlo amablemente, con páginas de documentación que faltan. Verifique esta pregunta casi idéntica que pregunta cómo enrutar dispositivos móviles
Panagiotis Kanavos

Respuestas:

227

Pude inicializar el httpcontext y el encabezado de esta manera:

[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
    ...
}
James Wierzba
fuente
21

En lugar de burlarse del HTTPContext, probablemente sea una mejor idea asignar el encabezado a un parámetro del método. Por ejemplo, en el controlador al final de esta respuesta, el idparámetro se establece en el encabezado de valor con un nombre igual a "id-dispositivo" ... La prueba unitaria se convierte

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

Si bien puede burlarse de HttpContext, en mi opinión, es algo que debe evitarse a menos que no tenga otra opción. La documentación para FromHeaderAttribute se puede encontrar aquí FromHeaderAttribute Class .

public class ValuesController: Controller
{
    public string GetHeaderValue([FromHeader(Name = "device-id")] string id)
    {
        return id;
    }
}
GlennSills
fuente
1
En mi caso, IIRC, era un requisito incluirlo en el encabezado http porque era necesario evaluar el mismo valor en un componente de middleware central .net
James Wierzba