Как выполнить модульное тестирование кода с помощью httpclient PostAsync и GetAsync с помощью nunit - PullRequest
0 голосов
/ 02 апреля 2019

У меня есть 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}&param1={param1}&param2={param2}&sub_param2={param3}&param4={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));
            }
        }
    }
}

1 Ответ

0 голосов
/ 02 апреля 2019

Я бы предложил разделить функциональность API и вашу логику.

Переместите оба http-вызова в логику и создайте HttpClient в конструкторе и не забудьте утилизировать.

Причина этого: 1. Вы можете написать тест маршрута, не реализуя все вещи HttpClient 2. Вы можете проверить свои вызовы HttpClient (post, get) с помощью обработанного обработчика http или макетировать 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}&param1={param1}&param2={param2}&sub_param2={param3}&param4={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

}

...