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.