Mock HttpContext pour les tests unitaires d'un contrôleur MVC .NET core?

94

J'ai une fonction dans un contrôleur que je teste unitaire qui attend des valeurs dans l'en-tête de la requête http. Je ne peux pas initialiser le HttpContext car il est en lecture seule.

La fonction de mon contrôleur attend une valeur d'en-tête de requête http pour "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-t-il un moyen simple de le faire sans utiliser une bibliothèque tierce?

James Wierzba
la source
1
N'utilisez pas HttpContext? L'intérêt de l'utilisation des contrôleurs est que les données passent par les paramètres du contrôleur. Si votre contrôleur utilise HttpContext pour lire des données comme s'il s'agissait d'une page WebForms, vous avez un problème.
Panagiotis Kanavos
@PanagiotisKanavos La valeur dans l'en-tête est une information indiquant de quel appareil mobile provient l'appel. Ceci est nécessaire pour récupérer les données correctes. L'ID d'appareil se trouve dans l'en-tête car l'ID est nécessaire pour l'authentification, qui est gérée par un filtre d'action personnalisé. Je pourrais passer l'identifiant de l'appareil en tant que paramètre d'itinéraire, mais ce serait redondant
James Wierzba
Vérifiez FromHeaderAttribute mais vérifiez également le doublon. HttpContext est injectable via la configuration maintenant
Panagiotis Kanavos
1
Je vous suggère de modifier votre question pour spécifier exactement ce que vous voulez (accès aux champs d'en-tête pour identifier les appareils mobiles). La documentation ASP.NET semble traverser une période de «transition» pour le dire gentiment, avec des pages de documentation manquantes. Cochez cette question presque identique qui demande comment router les appareils mobiles
Panagiotis Kanavos

Réponses:

226

J'ai pu initialiser le httpcontext et l'en-tête de cette manière:

[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
la source
21

Plutôt que de se moquer du HTTPContext, il est probablement préférable de mapper l'en-tête dans un paramètre de la méthode. Par exemple, dans le contrôleur en bas de cette réponse, le idparamètre est défini sur l'en-tête de valeur avec un nom égal à "device-id" ... Le test unitaire devient alors

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

Bien que vous puissiez vous moquer du HttpContext, à mon avis, c'est quelque chose qui devrait être évité à moins que vous n'ayez pas le choix. La documentation de la classe FromHeaderAttribute peut être trouvée ici FromHeaderAttribute Class .

public class ValuesController: Controller
{
    public string GetHeaderValue([FromHeader(Name = "device-id")] string id)
    {
        return id;
    }
}
GlennSills
la source
1
Dans mon cas, IIRC, il était nécessaire de l'inclure dans l'en-tête http car la même valeur devait être évaluée dans un composant middleware .net core
James Wierzba