2014-03-06 1 views
51

Microsoft.Net.Http을 사용하여 Json 데이터를 검색하는 서비스가 있습니다. 큰!.NET 테스트에서 조롱 한 HttpClient를 전달하는 방법은 무엇입니까?

물론 단위 테스트가 실제 서버에 적용되는 것을 원하지 않습니다. 그렇지 않으면 통합 테스트입니다.

여기에 내가 Moq 또는 FakeItEasy ... 말 ... 이것을 조롱 수있는 방법을 잘 모르겠어요 (의존성 주입을 사용하여 ...) 내 서비스의 ctor

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

입니다.

나는 내 서비스가 GetAsync 또는 PostAsync을 호출 할 때 그 전화를 가짜로 만들 수 있는지 확인하고 싶습니다.

어떻게 할 수 있습니까? 난 내 자신의 래퍼를 할 필요가 없습니다 -hoping-

는 난 .. 그의 쓰레기 :(Microsoft는이과 감독을 한 수 잘?

(예, 그것은 쉽게 원인 래퍼 만들기 .. 이전에 해봤지만 ... 요점입니다!)

+1

_ "나는 내 자신의 래퍼를 만들 필요가 없습니다."- 얼마나 많은'HttpClient' 메소드와 속성을 사용합니까? 일반적으로 이들을위한 인터페이스를 만드는 것이 유용 할 수 있습니다. 그런 다음이를 조롱 할 수 있습니다. – CodeCaster

+0

(내가 OP에서 언급 한 것처럼) 합의 - 쉽고 간단합니다 ...하지만 내가 가질 필요는 없지만 가질 수 있을까요? 이것은 핵심이되어야하는 것입니다 .. 맞습니까? 이게 유일한 방법인가요? –

+1

내가 아는 한, 가상 전화 일 경우 전화를 걸 수 있습니다. 그렇지 않은 경우 래퍼를 작성해야한다고 가정합니다 (이는 더 깨끗한 방법입니다). – ElGauchooo

답변

84

중핵 HttpMessageHandler를 가짜 것으로 바꿀 수 있습니다. 이 모양은 ...

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}; 
      } 

     } 
    } 

다음으로 위조 처리기를 사용할 클라이언트를 만들 수 있습니다.

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); 
+0

흥미로운 문제에 대한 좋은 해결책. 글자 그대로 HTTP를 통해 모든 것을 처리합니다. – Spence

+0

예제는 그대로 컴파일되지 않습니다. Task.FromResult를 사용하여 HttpResponseMessage 인스턴스를 반환해야합니다. – Ananke

+1

@Ananke SendAsync 메서드의 async 키워드는 당신을위한 마법을 만듭니다. –

1

Microsoft Fakes, 특히 Shims 섹션에서 살펴볼 수 있습니다.이 섹션을 사용하면 다음과 같은 동작을 수정할 수 있습니다. 귀하의 HttpClient 자체입니다. 필수 조건은 VS Premium 또는 Ultimate을 사용하는 것입니다.

+3

두 비싼 에디션에 대한 액세스 권한이 없습니다. –

2

난 그냥 await를 연산자를 기대 비동기 방식에 대한 경고를 피하기 위해 Task.FromResult을 사용 @Darrel Miller의 대답에 작은 변화를 만들 것입니다.

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 }); 
     } 
    } 
} 
+3

성능이 뛰어난 환경에서이 기술을 사용하는 데 신중을 기합니다. 이는 민감하지 않으므로 스레드 전환을 유발할 수 있습니다. 경고에 대해 정말로 염려하는 경우 async 키워드를 제거하고 Task.FromResult를 사용하십시오. –

+4

구현이 작업 기반이 아닌 경우 Task.FromResult를 반환하고 Task.Run을 사용하는 대신 async 키워드를 제거하는 것이 좋습니다. return Task.FromResult (response); – user3285954

17

나는이 오래된 질문은 알고 있지만, 나는이 주제에 대한 검색 동안 함께 발견 및 테스트 HttpClient 쉽게 만들 수있는 아주 좋은 해결책을 발견했다.

이 nuget를 통해 볼 수 있습니다 : 여기

https://github.com/richardszalay/mockhttp

PM> Install-Package RichardSzalay.MockHttp 

은 사용에 얼핏 경우 : GitHub의 프로젝트 페이지에

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'} 

더 자세한 정보는. 유용 할 수 있기를 바랍니다.

관련 문제