28 Stimmen

Stubbing oder Mocking ASP.NET Web API HttpClient

Ich verwende die neuen Web-API-Bits in einem Projekt, und ich habe festgestellt, dass ich nicht die normalen HttpMessageRequest da ich der Anforderung Client-Zertifikate hinzufügen muss. Als Ergebnis verwende ich die HttpClient (so kann ich die WebRequestHandler ). Dies alles funktioniert gut, außer, dass es nicht Stub/Mock freundlich, zumindest für Rhino Mocks ist.

Normalerweise würde ich einen Wrapper-Dienst um HttpClient die ich stattdessen verwenden würde, aber ich würde dies gerne vermeiden, wenn möglich, da es eine Menge Methoden gibt, die ich einpacken müsste. Ich hoffe, dass ich etwas übersehen habe - gibt es Vorschläge, wie man HttpClient ?

63voto

Tim Long Punkte 13230

Als Alternative zu den hervorragenden Ideen, die @Raj bereits vorgestellt hat, könnte man eine Stufe tiefer gehen und die HttpMessageHandler stattdessen.

Wenn Sie eine Klasse erstellen, die eine HttpClient als Parameter für die Injektion von Abhängigkeiten im Konstruktor akzeptieren, dann können Sie beim Unit-Test eine HttpClient das mit Ihrem eigenen Blut gespritzt wurde HttpMessageHandler . Diese einfache Klasse hat nur eine abstrakte Methode, die Sie wie folgt implementieren müssen:

public class FakeHttpMessageHandler : HttpMessageHandler
    {
    public HttpRequestMessage RequestMessage { get; private set; }

    protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
        {
        RequestMessage = request;
        return Task.FromResult(new HttpResponseMessage(HttpStatusCode.OK));
        }
    }

Mein triviales Beispiel speichert lediglich die HttpRequestMessage in einer öffentlichen Eigenschaft zur späteren Überprüfung und gibt HTTP 200 (OK) zurück, aber Sie könnten dies durch Hinzufügen eines Konstruktors erweitern, der das gewünschte Ergebnis festlegt.

Sie würden diese Klasse wie folgt verwenden:

public void foo()
    {
    //Arrange
    var fakeHandler = new FakeHttpMessageHandler();
    var client = new HttpClient(fakeHandler);
    var SUT = new ClassUnderTest(client);

    //Act
    SUT.DomSomething();

    //Assert
    fakeHandler.RequestMessage.Method.ShouldEqual(HttpMethod.Get); // etc...
    }

Dieser Ansatz hat seine Grenzen, zum Beispiel bei einer Methode, die mehrere Anfragen stellt oder mehrere HttpClient s, dann könnte der Fake-Handler zu kompliziert werden. Für einfache Fälle kann er jedoch eine Überlegung wert sein.

39voto

Richard Szalay Punkte 80740

Vor ein paar Monaten habe ich eine Bibliothek mit dem Titel MockHttp die nützlich sein könnten. Es verwendet eine benutzerdefinierte HttpMessageHandler mit einer fließenden (und erweiterbaren) API. Sie können den Mocked Handler (oder HttpClient) in Ihre Dienstklasse injizieren und er wird so reagieren, wie er konfiguriert wurde.

Im Folgenden wird die grundlegende Verwendung dargestellt. Die When y Respond Methoden haben eine Reihe von Überladungen, einschließlich der Ausführung benutzerdefinierter Logik. Die Dokumentation auf der GitHub-Seite geht sehr viel mehr ins Detail.

var mockHttp = new MockHttpMessageHandler();

// Setup a respond for the user api (including a wildcard in the URL)
mockHttp.When("http://localhost/api/user/*")
        .Respond("application/json", "{'name' : 'Test McGee'}"); // Respond with JSON

// Inject the handler or client into your application code
var client = new HttpClient(mockHttp);

var response = async client.GetAsync("http://localhost/api/user/1234");
// or without async: var response = client.GetAsync(...).Result;

var json = await response.Content.ReadAsStringAsync();

// No network connection required
Console.Write(json); // {'name' : 'Test McGee'}

11voto

Spock Punkte 6889

Ich verwende Moq und ich kann den HttpClient ausblenden. Ich denke, dies das gleiche für Rhino Mock (Ich habe nicht versucht, von mir). Wenn Sie nur den HttpClient stub wollen, sollte der folgende Code funktionieren:

var stubHttpClient = new Mock<HttpClient>();
ValuesController controller = new ValuesController(stubHttpClient.Object);

Bitte korrigieren Sie mich, wenn ich falsch liege. Ich vermute, Sie beziehen sich auf hier ist, dass Stubbing aus Mitglieder innerhalb HttpClient.

Die meisten populären Isolations-/Mock-Objekt-Frameworks erlauben kein Stub/Setup auf nicht virtuelle Mitglieder Zum Beispiel löst der folgende Code eine Ausnahme aus

stubHttpClient.Setup(x => x.BaseAddress).Returns(new Uri("some_uri");

Sie haben auch erwähnt, dass Sie vermeiden möchten, einen Wrapper zu erstellen, weil Sie viele HttpClient-Mitglieder einpacken würden. Nicht klar, warum Sie brauchen, um viele Methoden zu wickeln, aber Sie können leicht wickeln nur die Methoden, die Sie benötigen.

Zum Beispiel:

public interface IHttpClientWrapper  {   Uri BaseAddress { get;  }     }

public class HttpClientWrapper : IHttpClientWrapper
{
   readonly HttpClient client;

   public HttpClientWrapper()   {
       client = new HttpClient();
   }

   public Uri BaseAddress   {
       get
       {
           return client.BaseAddress;
       }
   }
}

Die anderen Optionen, von denen ich denke, dass sie für Sie von Vorteil sein könnten (es gibt viele Beispiele, daher werde ich den Code nicht schreiben) Microsoft Moles Framework http://research.microsoft.com/en-us/projects/moles/ Microsoft Fakes: (wenn Sie VS2012 Ultimate verwenden) http://msdn.microsoft.com/en-us/library/hh549175.aspx

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X