web-dev-qa-db-fra.com

Comment passer un HttpClient simulé dans un test .NET?

J'ai un service qui utilise Microsoft.Net.Http pour récupérer des données Json. Génial!

Bien sûr, je ne veux pas que mon test unitaire atteigne le serveur réel (sinon, c'est un test d'intégration).

Voici mon ctor de service (qui utilise l'injection de dépendances ...)

public Foo(string name, HttpClient httpClient = null)
{
...
}

Je ne sais pas comment je peux me moquer de ça avec ... disons .. Moq ou FakeItEasy.

Je veux m'assurer que lorsque mon service appelle GetAsync ou PostAsync .. alors je peux truquer ces appels.

Des suggestions sur la façon dont je peux faire cela?

Je suis en train de faire des achats - je n'ai pas besoin de faire mon propre Wrapper .. parce que c'est de la merde :( Microsoft ne peut pas avoir fait une erreur avec ça, non?

(oui, c'est facile de faire des emballages .. je les ai déjà fait ... mais c'est le point!)

55
Pure.Krome

Vous pouvez remplacer le noyau HttpMessageHandler par un faux. Quelque chose qui ressemble à ça ...

public class FakeResponseHandler : DelegatingHandler
    {
        private readonly Dictionary<Uri, HttpResponseMessage> _FakeResponses = new Dictionary<Uri, HttpResponseMessage>(); 

        public void AddFakeResponse(Uri uri, HttpResponseMessage responseMessage)
        {
                _FakeResponses.Add(uri,responseMessage);
        }

        protected async override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, System.Threading.CancellationToken cancellationToken)
        {
            if (_FakeResponses.ContainsKey(request.RequestUri))
            {
                return _FakeResponses[request.RequestUri];
            }
            else
            {
                return new HttpResponseMessage(HttpStatusCode.NotFound) { RequestMessage = request};
            }

        }
    }

puis vous pouvez créer un client qui utilisera le faux gestionnaire.

var fakeResponseHandler = new FakeResponseHandler();
fakeResponseHandler.AddFakeResponse(new Uri("http://example.org/test"), new HttpResponseMessage(HttpStatusCode.OK));

var httpClient = new HttpClient(fakeResponseHandler);

var response1 = await httpClient.GetAsync("http://example.org/notthere");
var response2 = await httpClient.GetAsync("http://example.org/test");

Assert.Equal(response1.StatusCode,HttpStatusCode.NotFound);
Assert.Equal(response2.StatusCode, HttpStatusCode.OK);
95
Darrel Miller

Je sais que c'est une vieille question, mais je suis tombée dessus lors d'une recherche sur ce sujet et j'ai trouvé une très belle solution pour faciliter les tests HttpClient.

Il est disponible via nuget:

https://github.com/richardszalay/mockhttp

PM> Install-Package RichardSzalay.MockHttp

Voici un bref aperçu de l'utilisation:

var mockHttp = new MockHttpMessageHandler();

// Setup a respond for the user api (including a wildcard in the URL)
mockHttp.When("http://localost/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 = await client.GetAsync("http://localost/api/user/1234");
// or without await: var response = client.GetAsync("http://localost/api/user/1234").Result;

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

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

Plus d'informations sur la page du projet github. J'espère que cela peut être utile.

18
Fedaykin

Je voudrais juste apporter une petite modification à la réponse de @ Darrel Miller , qui utilise Task.FromResult pour éviter l'avertissement à propos d'une méthode asynchrone attendant un opérateur d'attente.

public class FakeResponseHandler : DelegatingHandler
{
    private readonly Dictionary<Uri, HttpResponseMessage> _FakeResponses = new Dictionary<Uri, HttpResponseMessage>();

    public void AddFakeResponse(Uri uri, HttpResponseMessage responseMessage)
    {
        _FakeResponses.Add(uri, responseMessage);
    }

    protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, System.Threading.CancellationToken cancellationToken)
    {
        if (_FakeResponses.ContainsKey(request.RequestUri))
        {
            return Task.FromResult(_FakeResponses[request.RequestUri]);
        }
        else
        {
            return Task.FromResult(new HttpResponseMessage(HttpStatusCode.NotFound) { RequestMessage = request });
        }
    }
}
2
Rui Taborda

Vous pouvez jeter un œil à Microsoft Fakes , en particulier à la section Shims-. Avec eux, vous pouvez modifier les comportements de votre HttpClient lui-même. La condition préalable est que vous utilisiez VS Premium ou Ultimate.

1
ElGauchooo