Wir haben einige Klassen in unserem C# -Projekt, die Aufrufe an APIs von Drittanbietern ausführen. Wir verwenden HttpClient-Objekte für die Aufrufe. Wir haben unsere Klassen eingerichtet, in denen wir diese Aufrufe ausführen, um einen HttpClient zu akzeptieren, damit wir beim Testen einen benutzerdefinierten/falschen DelegatingHandler mit dem Client verwenden können.HttpClient.SendAsync verwendet DelegatingHandler beim Testen nicht
Wir haben unsere Klassen wie folgt aufgebaut:
public class CallingService : ApiService
{
private readonly ISomeOtherService _someOtherService;
public CallingService (ILogger logger,
IConfigurationManager configurationManager,
ISomeOtherService someOtherService) : base(logger, configurationManager)
{
_someOtherService = someOtherService;
}
public CallingService (ILogger logger,
HttpClient client,
IConfigurationManager configurationManager,
ISomeOtherService someOtherService) : base(logger, configurationManager, client)
{
_someOtherService = someOtherService;
}
private async Task<XmlNodeList> TransmitToApi(string xml_string)
{
ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3 | SecurityProtocolType.Tls12;
//..
string type = "application/xml";
var content = new StreamContent(new MemoryStream(Encoding.ASCII.GetBytes(xml_string)));
var targetUri = new Uri(ConfigurationManager.GetAppSetting("ApiUrl"));
var message = new HttpRequestMessage
{
RequestUri = targetUri ,
Method = HttpMethod.Post,
Content = content
};
message.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("*/*"));
message.Content.Headers.Add("Content-Type", type);
message.Headers.Add("someHeader", someData);
HttpResponseMessage response = null;
try
{
// Define the cancellation token.
CancellationTokenSource source = new CancellationTokenSource();
CancellationToken token = source.Token;
response = await Client.SendAsync(message, token);
}
catch (Exception ex)
{
throw ex;
}
//...
return someData;
}
Die Basis ApiService
-Klasse definiert ein generisches Objekt Httpclient, wenn man nicht vorgesehen ist.
Wir verwenden derzeit SendAsync, so dass wir die Nachrichtenheader definieren können. (Wir haben mehr Header als hier aufgelistet sind.)
Der Test der DelegatingHandler wie folgt definiert:
public class FakeResponseHandler : DelegatingHandler
{
private readonly Dictionary<Uri, HttpResponseMessage> _fakeResponses = new Dictionary<Uri, HttpResponseMessage>();
public void AddFakeResponse(Uri uri, HttpResponseMessage responseMessage, string content = "", bool asXml = false)
{
if (!string.IsNullOrWhiteSpace(content))
{
if (asXml)
{
responseMessage.Content = new StringContent(content, Encoding.UTF8, "application/xml");
}
else
{
responseMessage.Content = new StringContent(content, Encoding.UTF8, "application/json");
}
}
_fakeResponses.Add(uri, responseMessage);
}
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
if (_fakeResponses.ContainsKey(request.RequestUri))
{
return _fakeResponses[request.RequestUri];
}
return new HttpResponseMessage(HttpStatusCode.NotFound) { RequestMessage = request };
}
}
Und dann:
[Fact]
public async Task ItWillDoStuffAndCallApi()
{
using (var mock = AutoMock.GetLoose())
{
mock.Mock<IConfigurationManager>()
.Setup(cm => cm.GetAppSetting("ApiUrl"))
.Returns("http://example.org/test/");
string testReturnData = GetFileContents("IntegrationTests.SampleData.SampleApiResponseXML.txt");
FakeResponseHandler fakeResponseHandler = new FakeResponseHandler();
fakeResponseHandler.AddFakeResponse(new Uri("http://example.org/test/"),
new HttpResponseMessage(HttpStatusCode.OK),
testReturnData,
true);
//HttpClient httpClient = new HttpClient(fakeResponseHandler);
HttpClient httpClient = HttpClientFactory.Create(fakeResponseHandler);
mock.Provide(httpClient);
var ourService = new CallingService();
ourService.TransmitToApi(someXmlString);
}
}
Wenn wir den Test ausführen, erhalten wir die Nachricht :
Handler gab keine Antwortnachricht zurück.
Und wir scheinen nie in DelegatingHandler.SendAsync
Methode zu bekommen.
Wir haben andere Klassen aufrufen APIs mit HttpClient.PostAsync
oder GetAsync
, und diese rufen Sie die DelegatingHandler.SendAsync
Methode und funktionieren wie erwartet.
Wir haben versucht:
HttpClient httpClient = new HttpClient(fakeResponseHandler);
und
HttpClient httpClient = HttpClientFactory.Create(fakeResponseHandler);
Wir haben versucht, auch Client.SendAsync
mit und ohne Storno Token.
Warum funktioniert das nicht?
Sollten wir dies umschreiben, um PostAsync
zu verwenden?