Mock HttpContext per unit test di un controller MVC .NET core?


95

Ho una funzione in un controller che sto testando che prevede valori nell'intestazione della richiesta http. Non riesco a inizializzare HttpContext perché è di sola lettura.

La funzione del controller prevede un valore di intestazione della richiesta http per "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);
}

Esiste un modo semplice per farlo senza utilizzare una libreria di terze parti?


1
Non usi HttpContext? Il punto centrale dell'utilizzo dei controller è che i dati passano attraverso i parametri del controller. Se il tuo controller utilizza HttpContext per leggere i dati come se fosse una pagina WebForms, hai un problema.
Panagiotis Kanavos

@PanagiotisKanavos Il valore nell'intestazione è un'informazione che indica da quale dispositivo mobile proviene la chiamata. Ciò è necessario per recuperare i dati corretti. L'ID dispositivo è nell'intestazione perché l'ID è necessario per l'autenticazione, che viene gestita da un filtro di azione personalizzato. Potrei passare l'ID dispositivo come parametro di percorso, ma sarebbe ridondante
James Wierzba

Controlla FromHeaderAttribute ma controlla anche il duplicato. HttpContext è ora iniettabile tramite configurazione
Panagiotis Kanavos

1
Ti suggerisco di modificare la tua domanda per specificare esattamente ciò che desideri (accesso ai campi di intestazione per identificare i dispositivi mobili). La documentazione di ASP.NET sembra attraversare un ... periodo di "transizione" per dirla gentilmente, con pagine di documentazione mancanti. Controlla questa domanda quasi identica che chiede come instradare i dispositivi mobili
Panagiotis Kanavos

Risposte:


227

Sono stato in grado di inizializzare httpcontext e header in questo modo:

[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
    ...
}

21

Piuttosto che deridere HTTPContext, è probabilmente un'idea migliore mappare l'intestazione in un parametro del metodo. Ad esempio, nel controller in fondo a questa risposta, il idparametro è impostato sull'intestazione del valore con un nome uguale a "id-dispositivo" ... Lo unit test diventa quindi

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

Sebbene tu possa prendere in giro HttpContext, a mio parere è qualcosa che dovrebbe essere evitato a meno che tu non abbia scelta. La documentazione per FromHeaderAttribute può essere trovata qui FromHeaderAttribute Class .

public class ValuesController: Controller
{
    public string GetHeaderValue([FromHeader(Name = "device-id")] string id)
    {
        return id;
    }
}

1
Nel mio caso, IIRC, era obbligatorio includerlo nell'intestazione http perché lo stesso valore doveva essere valutato in un componente middleware .net core
James Wierzba
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.