Mock HttpContext do testowania jednostkowego kontrolera MVC .NET core?

102

Mam funkcję w kontrolerze, który jest testem jednostkowym, który oczekuje wartości w nagłówku żądania http. Nie mogę zainicjować HttpContext, ponieważ jest on tylko do odczytu.

Funkcja mojego kontrolera oczekuje wartości nagłówka żądania http dla „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);
}

Czy istnieje prosty sposób na zrobienie tego bez korzystania z biblioteki innej firmy?

James Wierzba
źródło
1
Nie używasz HttpContext? Cały sens korzystania z kontrolerów polega na tym, że dane przechodzą przez parametry kontrolera. Jeśli kontroler używa HttpContext do odczytywania danych tak, jakby była to strona formularzy sieci Web, masz problem.
Panagiotis Kanavos
@PanagiotisKanavos Wartość w nagłówku to informacja wskazująca, z jakiego urządzenia mobilnego pochodzi połączenie. Jest to konieczne, aby pobrać prawidłowe dane. Identyfikator urządzenia znajduje się w nagłówku, ponieważ jest on potrzebny do uwierzytelnienia, które jest obsługiwane przez niestandardowy filtr akcji. Mógłbym przekazać identyfikator urządzenia jako parametr trasy, ale byłby on zbędny
James Wierzba
Sprawdź FromHeaderAttribute, ale także sprawdź duplikat. HttpContext można teraz wstrzykiwać poprzez konfigurację
Panagiotis Kanavos
1
Proponuję edytować swoje pytanie, aby dokładnie określić, czego chcesz (dostęp do pól nagłówka w celu identyfikacji urządzeń mobilnych). Wydaje się, że dokumentacja ASP.NET przechodzi… okres „przejściowy”, delikatnie mówiąc, z brakującymi stronami z dokumentacją. Sprawdź to prawie identyczne pytanie, które pyta, jak
trasować

Odpowiedzi:

233

Udało mi się zainicjować httpcontext i nagłówek w ten sposób:

[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
źródło
21

Zamiast wyszydzać HTTPContext, prawdopodobnie lepszym pomysłem jest zamapowanie nagłówka na parametr metody. Na przykład w kontrolerze na dole tej odpowiedzi idparametr jest ustawiony na nagłówek wartości o nazwie równej „identyfikator urządzenia” ... Test jednostkowy staje się wtedy

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

Podczas można drwić HttpContext, moim zdaniem to jest coś, co powinno się unikać, chyba że nie masz wyboru. Dokumentację dotyczącą FromHeaderAttribute można znaleźć tutaj FromHeaderAttribute Class .

public class ValuesController: Controller
{
    public string GetHeaderValue([FromHeader(Name = "device-id")] string id)
    {
        return id;
    }
}
GlennSills
źródło
1
W moim przypadku, IIRC, wymagane było umieszczenie go w nagłówku http, ponieważ ta sama wartość musiała zostać oszacowana w komponencie pośredniczącym .net core
James Wierzba