我有一个ApiController,我有2个调用来获取外部APis-httpClient.PostAsync和httpClient.GetAsync的响应。
我可以获得一些关于UnitTesting(Nunit)的建议 - httpClient.PostAsync和httpClient.GetAsync交互。
以下代码片段 -
[System.Web.Http.RoutePrefix("api/v1/testApi")]
[System.Web.Http.AllowAnonymous]
public class TestApiController : ApiController
{
//get settings data from config file -TestFetchTokenLogin , TestFetchTokenKey , TestFetchTokenUri etc
[System.Web.Http.Route("gettestapi")]
[ValidateAntiForgeryToken]
public IHttpActionResult GetTestAPI(string param1 = "", string param2 = "", string param3 = "", string param4 = "")
{
ApiDataResponse dataResponse;
var httpClient = new HttpClient(new HttpClientHandler { UseProxy = false });
try
{
List<KeyValuePair<string, string>> fetchTokenrequest = new List<KeyValuePair<string, string>>
{
new KeyValuePair<string, string>("login", TestFetchTokenLogin),
new KeyValuePair<string, string>("password", TestFetchTokenKey)
};
FormUrlEncodedContent fetchTokenrequestBody = new FormUrlEncodedContent(fetchTokenrequest);
var fetchTokenResponse = httpClient.PostAsync(TestFetchTokenUri, fetchTokenrequestBody);
if (fetchTokenResponse != null)
{
var tokenResponse = JToken.Parse(fetchTokenResponse.Result.Content.ReadAsStringAsync().Result);
var token = tokenResponse?.SelectToken("access_token")?.ToString();
if (!string.IsNullOrWhiteSpace(token))
{
var apiResponse = httpClient.GetAsync($"{TestFetchDataUri}?restapi.session_key={token}¶m1={param1}¶m2={param2}&sub_param2={param3}¶m4={param4}&OutputFormat=json");
var task = apiResponse.Result.Content.ReadAsStringAsync();
dataResponse = new ApiDataResponse
{
Success = true,
Response = task.Result
};
return ResponseMessage(Request.CreateResponse(HttpStatusCode.OK, dataResponse));
}
dataResponse = new ApiDataResponse
{
Success = false,
Response = "access_token not exists in the response"
};
return ResponseMessage(Request.CreateResponse(HttpStatusCode.NoContent, dataResponse));
}
dataResponse = new ApiDataResponse
{
Success = false,
Response = "token response empty or null"
};
return ResponseMessage(Request.CreateResponse(HttpStatusCode.InternalServerError, dataResponse));
}
catch (Exception ex)
{
dataResponse = new ApiDataResponse
{
Success = false,
Response = ex.Message
};
return ResponseMessage(Request.CreateResponse(HttpStatusCode.InternalServerError, dataResponse));
}
}
}
}
我建议拆分api功能和你的逻辑。
将两个http调用移动到逻辑并在构造函数中创建HttpClient,并且不要忘记dispose。
原因:1。你可以在不实现所有HttpClient东西的情况下编写路由测试2.你可以使用模拟的http处理程序测试HttpClient调用(post,get)或模拟HttpClient - >如果你注入它们,两者都是可能的通过逻辑中的构造函数
请执行async - await模式正确。
我做了一个快速拆分 - 我将处理这样的逻辑(见下文)并从api调用这个逻辑。
public class TestLogic : IDispose {
private HttpClientHandler _Handler;
// I would handle the login and password in a own config object
public TestLogic(HttpClientHandler handler, Config config )
{
_Handler = handler ?? throw new ArgumentException();
}
public async Task<ApiDataResponse> PostfetchTokenrequestBodyAsync()
{
List<KeyValuePair<string, string>> fetchTokenrequest = new List<KeyValuePair<string, string>>
{
new KeyValuePair<string, string>("login", TestFetchTokenLogin),
new KeyValuePair<string, string>("password", TestFetchTokenKey)
};
FormUrlEncodedContent fetchTokenrequestBody = new FormUrlEncodedContent(fetchTokenrequest);
var fetchTokenResponse = await httpClient.PostAsync(TestFetchTokenUri, fetchTokenrequestBody).ConfigurationAwait(false);
fetchTokenResponse.EnsureSuccessStatusCode();
var tokenResponse = JToken.Parse(await fetchTokenResponse.ReadAsStringAsync().ConfigurationAwait(false));
var token = tokenResponse?.SelectToken("access_token")?.ToString();
return tokenResponse;
}
public async Task<ApiDataResponse> GetHinterlandFetchDataUriAsync(string token, ...)
{
var apiResponse = httpClient.GetAsync($"{HinterlandFetchDataUri}?restapi.session_key={token}¶m1={param1}¶m2={param2}&sub_param2={param3}¶m4={param4}&OutputFormat=json");
apiResponse.EnsureSuccessStatusCode(); // handle exception
var result = await apiResponse.Result.Content.ReadAsStringAsync().ConfigurationAwait(false);
return = new ApiDataResponse
{
Success = true,
Response = result
};
}
// implement IDisposable interface correct https://docs.microsoft.com/de-de/dotnet/api/system.idisposable?view=netframework-4.7.2
}