Decouble REST Test Automation Framework из тестов - PullRequest
0 голосов
/ 26 апреля 2020

Надеюсь, что все в целости и сохранности во время экстренного события covid-19 ...

Я создаю среду автоматизации тестирования, используя C# in. Net Core. Мы также используем SpecFlow для реализации BDD. Я работаю над поддержкой REST API и пытаюсь отделить REST DTO, который используется для управления ответом от фреймворка - я использую Generics для этого. Я работал с шаблонами в Java и предоставил некоторый код о том, как мы реализовали это в Java с помощью Spring ... Попытка переместить этот дизайн в C# ...

Извините, это так долго - может быть, некоторая помощь для других людей.

Спасибо за любую помощь.

Вот реализация Java (рабочая) - будет предпринята попытка C# ...


// Test Implementation 
// The details of the test (DTO) are decoupled from the test automation 
// framework using the Templated of the RESTResponse Class 

// Feature File (Test)

@service
Feature: Case Category Service
  Background:
  Scenario Outline: Verify retrieving case category
    When I call the get case category service
      | Case Category ID   |
      | <Case Category ID> |
    Then I will get the case category service response:
      | Case Category ID   | Case Category Name   | Case Category Comment   |
      | <Case Category ID> | <Case Category Name> | <Case Category Comment> |
    Examples:
      | Case Category ID | Case Category Name | Case Category Comment  |
      | 1000000          | Appeal             | These are appeal cases |

Java Реализация (рабочая)

Файл шага Реализация (тест)

Обратите внимание, как CountyResponseDTO в ответе использует шаблон RESTResponse


@When("^I call the get county service:$")
public void getCounty(DataTable table) throws Throwable
{
    RESTResponse<CountyResponseDTO> response = countyService.getCounty(new BaseDataTable(table));
    globals.put("countyResponse", response.getObject());
}

@Then("^I will get the county service response:$")
public void validateCountyServiceResponse(DataTable table) throws Throwable
{
    BaseDataTable t = new BaseDataTable(table);
    CountyResponseDTO responseDTO = globals.get("countyResponse");

    softAssert.assertEquals("ID from cucumber table matches DTO response ID", 
                            t.getValue("County ID"),
                            responseDTO.getCountyID());
    softAssert.process();
}

Java Реализация (рабочая)

Реализация сервиса (тест)


@QAComponent("caseCategoryService")
public class CaseCategoryService extends AbstractRESTService
{
    // Returns a case catgory.
    public RESTResponse<CaseCategoryResponseDTO> getCaseCategory(BaseDataTable table)
    {
        return get(CaseCategoryResponseDTO.class, "caseCategoryService.getCaseCategory.v1",
                table.getValue("Case Category ID"));
    }
}

Java Реализация (рабочая)

Test Automation Framework

Отсоединяется от вышеуказанного теста с использованием шаблонного RESTResponse

Реализация RestClient (Framework)

// Issues an HTTP get request, for returning a resource from the system.
protected <T> RESTResponse<T> get(Class<T> responseClass, String pathKey, String... pathValues)
{
    return get(null, responseClass, pathKey, pathValues);
}

Java Реализация (рабочая)

Реализация RestClient (Framework)

// Issues an HTTP get request, for returning a resource from the system
protected <T> RESTResponse<T> get(Map<String, String> params, Class<T> responseClass, String pathKey, String... pathValues)
{
    RESTResponse response = null;
    StringBuilder builder = new StringBuilder(getURL(pathKey, pathValues));
    if (params != null && params.size() > 0)
    {
        builder.append("?");
        for (Map.Entry<String, String> entry : params.entrySet())
        {
            builder.append(entry.getKey() + "=" + entry.getValue());
        }
    }

    try
    {
        log.debug("Sending GET request: " + builder.toString());
        ResponseEntity<T> r = template.exchange(builder.toString(), HttpMethod.GET, 
        new HttpEntity<Object>(
                getHeader()), responseClass);
        response = new RESTResponse(r.getBody(), r.getStatusCode().value(), r.getHeaders());
    }
    catch (HttpClientErrorException exc)
    {
        response = new RESTResponse(null, exc.getStatusCode().value(), exc.getResponseHeaders());
        String errorMessage = exc.getResponseBodyAsString();
        response.setErrorMessage(errorMessage);
        log.debug("Response error message: " + errorMessage);
    }
    log.debug("Response code: " + response.getHttpStatusCode());
    return response;
}

Java Реализация (рабочая)

Реализация RestClient, RESTResponse (Framework)


public class RESTResponse<T>
{
    private T object;
    private int httpStatusCode;
    private String errorMessage;
    private HttpHeaders headers;

    // Initializing constructor.
    public RESTResponse(T object, int httpStatusCode, HttpHeaders headers)
    {
        this.object = object;
        this.httpStatusCode = httpStatusCode;
        this.headers = headers;
    }

    // Returns the object associated with this response. Returns null if no object was received.
    public T getObject()
    {
        return object;
    }

    // Returns the HTTP status code associated with this response.
    public int getHttpStatusCode()
    {
        return httpStatusCode;
    }

    // Convenience wrapper for quickly getting the ID header.
    public String getIDHeader()
    {
        return getHeader("id");
    }

    // Returns the HTTP header value for the specified header name.
    public String getHeader(String headerName)
    {
        return headers.get(headerName).get(0);
    }

    // Returns the error message associated with this response. 
    // Returns null if no error message is available.
    public String getErrorMessage()
    {
        return errorMessage;
    }

    // Sets the error message associated with this response.
    public void setErrorMessage(String errorMessage)
    {
        this.errorMessage = errorMessage;
    }
}

C# Реализация (справка)

C# Реализация (справка)

Опять же - мы пытаемся реализовать подобный дизайн в C#. Я отмечу в реализации REST Get (), где у меня есть некоторые проблемы с использованием Generics в десериализации ответа.

Здесь много кода - извините, я добавил комментарий HELP ниже - где я думаю, что мне нужно HELP


// Feature File (SpecFlow BDD)

@service
Feature: RestClient Test
    In order to test the RestClient implementation using the Automation Framework
    As a Software Engineer testing the Automation Framework
    I want to see that the RestClient works with the standard Http Methods the Framework

@mytag
Scenario: Implment and test the Http Get Method
    Given I have access to the host system
    When I provide the record id to the Get Method URL as 10
    Then the Get Method will return the response as expected as 200

C# Реализация (Справка)

Реализация определения шага (SpecFlow)

[Then(@"the Get Method will return the response as expected as (.*)")]
public void ThenTheGetMethodWillReturnTheResponseAsExpectedAs(int expectedHttp)
{
    logger.Debug("Inside: RestClientTestSteps::ThenTheGetMethodWillReturnTheResponseAsExpectedAs()");
    logger.Debug("expectedHttp: {0} ", expectedHttp);

    // ****************
    // ***** HELP *****
    // ****************

    // Don't know how to use generics to get the response in the 
    // form of the RepositoryDto retuendd from the Get() from the framework
    // This will not work 
    RepositoryDto responseDTO<RepositoryDto> = baseRestClient.Get("https://api.github.com/orgs/dotnet/repos", 
                   typeof(RepositoryDto));

    // Now we will test 
    softAssert.assertEquals("HTTP Result from SpecFlow matches DTO response ID", 
                            expectedHttp,
                            responseDTO.getHttpStatusCode());
    softAssert.process();
}

C# Реализация (справка)

Framework REST Get Реализация

Использование универсальных шаблонов и шаблонов

public Object Get(string url, Type responseClass)
{
    client.DefaultRequestHeaders.Accept.Clear();
    client.DefaultRequestHeaders.Accept.Add(
            new MediaTypeWithQualityHeaderValue("application/vnd.github.v3+json"));
    client.DefaultRequestHeaders.Add("User-Agent", ".NET Foundation Repository Reporter");

    // ****************
    // ***** HELP *****
    // ****************

    // Again, attempting to decouple this Get() method from the Response DTO that is 
    // specific to the test. We are passing in the DTO Object and then using 
    // Activator.CreateInstance() to create the object. 

    // Then I need to serialize the response from the GetStringAsync() call into 
    // the Response DTO object ??? 

    Object theObject = Activator.CreateInstance(responseClass).;

    var response = client.GetStringAsync(new Uri(url)).Result;
    repositories = JsonSerializer.Deserialize<List<responseClass>> (response);

    return repositories;
}

C# Реализация

Класс ответа REST с использованием Generics

public class BaseRestResponse<T>
{
    private T Object;
    private int httpStatusCode;
    private string errorMessage;
    private HttpHeaders headers;

    public BaseRestResponse(T input, int httpStatusCode, HttpHeaders headers)
    {
        this.Object = input;
        this.httpStatusCode = httpStatusCode;
        this.headers = headers;
    }

    public T getObject()
    {
        return Object;
    }

    public int getHttpStatusCode()
    {
        return httpStatusCode;
    }

    public string getIDHeader()
    {
        return getHeader("id");
    }

    public string getHeader(string headerName)
    {
        return headers.GetValues(headerName).ToString();
    }

    public string getErrorMessage()
    {
        return errorMessage;
    }

    public void setErrorMessage(String errorMessage)
    {
        this.errorMessage = errorMessage;
    }
}

Еще раз спасибо за любые предложения

Оставайтесь в безопасности ...

Спасибо, Крис

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...