Mock HttpContext para teste de unidade de um controlador MVC .NET core?

93

Eu tenho uma função em um controlador que estou testando unidade que espera valores no cabeçalho da solicitação http. Não consigo inicializar o HttpContext porque ele é somente leitura.

Minha função de controlador espera um valor de cabeçalho de solicitação http para "device-id"

[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 uma maneira direta de fazer isso sem usar uma biblioteca de terceiros?

James Wierzba
fonte
1
Não usa HttpContext? O objetivo do uso de controladores é que os dados vêm através dos parâmetros do controlador. Se o seu controlador usa o HttpContext para ler dados como se fossem uma página de WebForms, você tem um problema.
Panagiotis Kanavos
@PanagiotisKanavos O valor no cabeçalho é uma informação que indica de qual dispositivo móvel vem a chamada. Isso é necessário para recuperar os dados corretos. O ID do dispositivo está no cabeçalho porque o ID é necessário para autenticação, que é tratada por um filtro de ação personalizado. Eu poderia passar o ID do dispositivo como um parâmetro de rota, mas seria redundante
James Wierzba
Verifique FromHeaderAttribute, mas também verifique a duplicata. HttpContext é injetável por meio de configuração agora
Panagiotis Kanavos
1
Eu sugiro que você edite sua pergunta para especificar exatamente o que você deseja (acesso aos campos de cabeçalho para identificar dispositivos móveis). A documentação do ASP.NET parece estar passando por um .... período de "transição" para ser gentil, com páginas de documentação faltando. Verifique esta pergunta quase idêntica que pergunta como rotear dispositivos móveis
Panagiotis Kanavos

Respostas:

224

Consegui inicializar o httpcontext e o cabeçalho desta maneira:

[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
fonte
20

Em vez de zombar do HTTPContext, provavelmente é uma ideia melhor mapear o cabeçalho em um parâmetro no método. Por exemplo, no controlador na parte inferior desta resposta, o idparâmetro é definido como o cabeçalho do valor com um nome igual a "id do dispositivo" ... O teste de unidade então se torna

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

Embora você possa zombar do HttpContext, na minha opinião é algo que deve ser evitado, a menos que você não tenha escolha. A documentação para FromHeaderAttribute pode ser encontrada aqui FromHeaderAttribute Class .

public class ValuesController: Controller
{
    public string GetHeaderValue([FromHeader(Name = "device-id")] string id)
    {
        return id;
    }
}
GlennSills
fonte
1
No meu caso, IIRC, era um requisito incluí-lo no cabeçalho http porque o mesmo valor precisava ser avaliado em um componente de middleware central
James Wierzba