Mock HttpContext zum Testen eines .NET Core MVC-Controllers?

93

Ich habe eine Funktion in einem Controller, die ich als Unit-Test durchführe und die Werte im Header der http-Anforderung erwartet. Ich kann den HttpContext nicht initialisieren, da er schreibgeschützt ist.

Meine Controller-Funktion erwartet einen http-Anforderungsheaderwert für "Geräte-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);
}

Gibt es eine einfache Möglichkeit, dies zu tun, ohne eine Bibliothek eines Drittanbieters zu verwenden?

James Wierzba
quelle
1
Sie nicht Httpcontext verwenden? Der springende Punkt bei der Verwendung von Controllern ist, dass die Daten über die Parameter des Controllers übertragen werden. Wenn Ihr Controller den HttpContext zum Lesen von Daten verwendet, als wäre es eine WebForms-Seite, liegt ein Problem vor.
Panagiotis Kanavos
@PanagiotisKanavos Der Wert in der Kopfzeile gibt an, von welchem ​​Mobilgerät der Anruf stammt. Dies ist erforderlich, um die richtigen Daten abzurufen. Die Geräte-ID befindet sich im Header, da die ID für die Authentifizierung benötigt wird, die von einem benutzerdefinierten Aktionsfilter verarbeitet wird. Ich könnte die Geräte-ID als Routenparameter übergeben, aber sie wäre redundant
James Wierzba
Überprüfen Sie FromHeaderAttribute, aber überprüfen Sie auch das Duplikat. HttpContext ist jetzt durch Konfiguration injizierbar
Panagiotis Kanavos
1
Ich schlage vor, Sie bearbeiten Ihre Frage, um genau anzugeben, was Sie möchten (Zugriff auf Header-Felder zur Identifizierung mobiler Geräte). Die ASP.NET-Dokumentation scheint eine "Übergangsphase" zu durchlaufen, um es freundlich auszudrücken, da Dokumentationsseiten fehlen. Überprüfen Sie diese fast identische Frage , die fragt, wie mobile Geräte zu routen
Panagiotis Kanavos

Antworten:

224

Ich konnte den httpcontext und den Header folgendermaßen initialisieren:

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

Anstatt den HTTPContext zu verspotten, ist es wahrscheinlich eine bessere Idee, den Header einem Parameter der Methode zuzuordnen. In der Steuerung am Ende dieser Antwort wird der idParameter beispielsweise auf den Wertekopf mit einem Namen gesetzt, der gleich "Geräte-ID" ist ... Der Komponententest wird dann

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

Sie können den HttpContext zwar verspotten, aber meiner Meinung nach sollte er vermieden werden, es sei denn, Sie haben keine andere Wahl. Die Dokumentation zum FromHeaderAttribute finden Sie hier FromHeaderAttribute Class .

public class ValuesController: Controller
{
    public string GetHeaderValue([FromHeader(Name = "device-id")] string id)
    {
        return id;
    }
}
GlennSills
quelle
1
In meinem Fall, IIRC, war es erforderlich, es in den http-Header aufzunehmen, da derselbe Wert in einer .net-Core-Middleware-Komponente ausgewertet werden musste
James Wierzba