Guia importante para testes de API Rest & RestAssured

Neste tutorial de descanso garantido exaustivo, vamos aprender o Teste de API Rest em profundidade, Automação de Teste de API e Rest Assured em abordagem modular

O que é RestAssured e seu uso

Rest Assured é uma tecnologia de código aberto amplamente usada para REST API Automation Testing, baseada em biblioteca baseada em java.

Rest Assured interage com a API Rest em um modo cliente sem cabeça, podemos aprimorar a mesma solicitação adicionando diferentes camadas para formar a solicitação e criar uma solicitação HTTP por meio de diferentes verbos HTTPS para o servidor.

A biblioteca integrada Rest Assured fornece métodos e utilitários enormes para realizar a validação da resposta recebida do servidor, como mensagem de status, código de status e corpo de resposta.

Esta série completa de Tutorial de descanso garantido para teste de automação de API REST consiste nos seguintes tópicos:

RestAssured -O teste da API do tutorial do descanso assegurado
Automação de API Rest Assured

Primeiros passos: configuração do restAssured com a ferramenta Build, ou seja, Maven / gradle

ETAPA 1: se você estiver trabalhando com o maven, basta adicionar a seguinte dependência em pom.xml (você também pode escolher qualquer outra versão):

Para começar com REST Assured, basta adicionar a dependência ao seu projeto. 


    io.rest-assegurado
    tenha certeza
    4.3.0
    teste

Se você estiver trabalhando com o gradle, basta adicionar o seguinte em build.gradle (novamente, você também pode escolher qualquer outra versão):

Grupo testCompile: 'io.rest-assegurado', nome: 'descanso assegurado', versão: '4.3.0'

PASSO 2: REST Assured pode ser integrado e usado muito facilmente com as estruturas de teste de unidade existentes, ou seja, Testng, JUnit

Aqui, estamos usando testNg de acordo com a Estrutura de Teste de Unidade em questão.

Depois que as bibliotecas do Rest Assured forem importadas, precisamos adicionar as seguintes importações estáticas às nossas classes de teste:

import static io.restassured.RestAssured. *;

import static org.hamcrest.Matchers. *;

NOTA: Para este futuro propósito de aprendizagem, vamos testar a API Ergast Developer, que podem ser encontrados aqui. Esta API fornece dados históricos relacionados a corridas de Fórmula 1, pilotos, circuitos, etc.

Familiaridade com a sintaxe:

Rest Assured é compatível com o formato BDD (Sintaxe de pepino) para escrever os scripts de teste, ou seja, no formato Dado / Quando / Então / E, presumimos que você entenda a sintaxe BDD / gherkin. Caso contrário, sugerimos que você gaste 30 minutos para entender o que é BDD (Sintaxe de pepino) e como funciona e é muito básico.

T-01: Nosso primeiro script que está basicamente validando o número de circuitos na F1 em 1 usando esta API (http://ergast.com/api/f1/2017/circuits.json)

@Test (description = "Número de circuitos na temporada de 2017 deve ser 20") public void validatingNumberOfCircuits () {given (). When (). Get ("http://ergast.com/api/f1/2017/circuits. json "). then (). assertThat (). body ("MRData.CircuitTable.Circuits.circuitId", hasSize (20)); }

Validação de resposta da API Rest :

1. Captura a resposta JSON da solicitação de API.

2. Consultas para circuitId usando a expressão GPath “MRData.CircuitTable.Circuits.circuitId”

3. Verifica se a coleção de elementos circuitId tem o tamanho de 20

Aqui estamos usando Matchers Hamcrest para várias validações, como

Existem vários outros métodos que são úteis para realizar certas validações.

Além disso, você pode consultar a documentação da biblioteca Hamcrest para uma lista completa de matchers e métodos.

Validando o código de resposta:

dado (). quando (). get ("http://ergast.com/api/f1/2017/circuits.json") .then (). assertThat (). statusCode (200);

Validação do tipo de conteúdo

dado (). when (). get ("http://ergast.com/api/f1/2017/circuits.json") .then (). assertThat (). contentType (ContentType.JSON);

Validando o cabeçalho “Content-Length”

dado (). quando (). get ("http://ergast.com/api/f1/2017/circuits.json") .then (). assertThat (). header (" Content-Length ", equalTo (" 4551 "));

Validação múltipla em um único testes como (usando os métodos e ()):

@Test (descrição = "Número de circuitos na temporada de 2017 deve ser 20")
    public void validatingNumberOfCircuits () {
        given (). when (). get ("http://ergast.com/api/f1/2017/circuits.json") .then (). assertThat (). header ("Content-Length", equalTo (" 4551 ")). E (). StatusCode (200);
    }

Validando elemento / atributo do corpo de resposta:

Podemos usar JsonPath para buscar o valor dos atributos json e colocar asserção usando TestNg

@Test (descrição = "Validação do nome da série que é f1")
    public void validatingSeriesName () {
        // Converter ResponseBody em String
        String responseBody = given (). When (). Get ("http://ergast.com/api/f1/2017/circuits.json") .getBody (). AsString ();
        // Criar objeto JsonPath passando o corpo da resposta como uma string
        JsonPath resJson = novo JsonPath (responseBody);
        // Buscar a série de valores do atributo em MRData
        String seriesName = resJson.getString ("MRData.series");
        // Asserção do usuário TestNg
        Assert.assertEquals ("f1", seriesName);
    }

Da mesma forma, poderíamos obter o valor da resposta XML usando XMLPath. Aqui estamos trabalhando com JSON, portanto, usamos aqui JSonPath

APIs RESTful suportam apenas dois tipos de parâmetros:

A. Parâmetros de consulta: Aqui, os parâmetros são anexados ao final do endpoint da API e podem ser identificados pelo ponto de interrogação e formam um par de valores-chave, como 

https://www.google.com/search?q=https://www.wikipedia.org/

Aqui na API acima, 'q' é o parâmetro e 'https://www.wikipedia.org/' é o valor desse parâmetro, se pesquisarmos 'ALGO_ELSE_TEXTO'poderíamos substituir o valor do parâmetro 'q' com 'ALGO_ELSE_TEXTO'no lugar de https://www.wikipedia.org/.

B. Parâmetros de caminho: Eles fazem parte do endpoint da API RESTful. 

por exemplo. endpoint que usamos anteriormente: http://ergast.com/api/f1/2017/circuits.json, aqui “2017” é um valor de parâmetro de caminho.

Para obter o resultado do ano 2016, poderíamos substituir 2017 por 2016 então, a API fornecerá o corpo da resposta para 2016.

Testes usando parâmetros de caminho para RestAssured

@Test (descrição = "Validação do número de circuitos usando parâmetros de caminho")
    public void testWithPathParams () {
        String seasonNumber = "2017";
       String responseBody = given (). PathParam ("season", seasonNumber) .when (). Get ("http://ergast.com/api/f1/{season}/circuits.json") .getBody (). AsString ();
        // Criar objeto JsonPath passando o corpo da resposta como uma string
        JsonPath resJson = novo JsonPath (responseBody);
        // Buscar a série de valores do atributo em MRData
        String seriesName = resJson.getString ("MRData.series");
        // Asserção do usuário TestNg
        Assert.assertEquals ("f1", seriesName);
    }

Testes usando parâmetros de consulta para RestAssured

@Test (description = "Validation of Google search using Query Params")
    public void testWithPathParams () {
        String searchItem = "https://www.wikipedia.org/";
  given (). queryParam ("q", searchItem) .when (). get ("https://www.google.com/search") .then (). assertThat (). statusCode (200);
    }

Parametrizando testes:

Podemos fazer testes orientados a dados (ou seja, o mesmo script de teste será executado várias vezes com diferentes conjuntos de dados de entrada e fornecer dados de saída diferentes) usando Rest Assured 

PASSO 1: Criado um provedor de dados testNg.

ETAPA 2: consumir o provedor de dados no script de teste.

@DataProvider (name = "seasonsAndRaceNumbers")
    public Object [] [] testDataFeed () {
        return new Object [] [] {
                {"2017", 20},
                {"2016", 21}
        };
    }
@Test (description = "Validação de número de circuitos em estações diferentes", dataProvider = "Seasonsandracenumbers.") public void circuitNumberValidation (String seasonYear, int raceNumbers) {given ().pathParam ("season", seasonYear) .when (). get ("http://ergast.com/api/f1/{temporada}/circuits.json "). then (). assertThat (). body (" MRData.CircuitTable.Circuits.circuitId ", hasSize (RaceNumbers)); }

Trabalhando com parâmetros multivalorados com RestAssured 

Parâmetros de vários valores são aqueles parâmetros que têm mais de um valor por nome de parâmetro (ou seja, uma lista de valores por paramKey), podemos abordá-los como abaixo:

given (). param ("paramKey", "paramValue1", "paramaValue2"). when (). get (“API URL“);

Ou podemos preparar uma lista e passar a lista como o valor de paramKey como:

Lista paramValue = novo novo ArrayList ();
paramValue.add (“paramvalue1”);
paramValue.add (“paramvalue2);
given (). param ("paramKey", paramValue) .when (). get (“API URL“);
Trabalhando com cookie com RestAssured 
given (). cookie ("cookieK", "cookieVal"). when (). get ("URL API");

Or 

Também podemos especificar um cookie de vários valores aqui, como:

given (). cookie ("cookieK", "cookieVal1", "cookieVal2"). when (). get (“URL da API”);

Trabalhando com cabeçalhos:

Podemos especificar em uma solicitação usando cabeçalho / cabeçalhos como:

dado (). header (“headerK1”, ”headerValue1”). header (“headerK2”, ”headerValue2”). when (). get (“API URL”);

Trabalhando com contentType:

given (). contentType ("application / json"). when (). get (“URL da API”);

Or 

dado (). contentType (ContentType.JSON) .when (). get ();

Meça o tempo de resposta:

long timeDurationInSeconds = get (“URL da API”). timeIn (SECONDS);

Autenticação de API Rest

O REST garantido suporta diferentes esquemas de autenticação, por exemplo, OAuth, digest, certificado, formulário e autenticação básica preemptiva. Podemos definir autenticação para cada solicitação 

aqui está um exemplo de solicitação usando o mesmo:

given (). auth (). basic ("uNome", "pwd"). when (). get (“URL“) ..

Por outro lado, a autenticação e definida na abordagem abaixo para as solicitações HTTP:

RestAssured.authentication = basic ("uName", "pwd");

Tipos básicos de AUTH:

Existem dois tipos de autenticação básica, “preemptiva” e “autenticação básica de token desafiado”.

Autenticação básica preemptiva:

Isso enviará a credencial de autenticação básica antes mesmo que o servidor dê uma resposta não autorizada em certas situações junto com a solicitação sendo acionada, reduzindo assim a sobrecarga de fazer uma conexão adicional. Normalmente, isso ocorre principalmente em situações, a menos que estejamos testando a capacidade de desafio dos servidores. 

Por exemplo.

given (). auth (). preemptive (). basic ("uNome", "pwd"). when (). get ("URL"). then (). statusCode (200);

Autenticação básica desafiada

Por outro lado, o REST Assured de “autenticação básica desafiada” não fornecerá as credenciais, a menos que o servidor as tenha solicitado explicitamente, ou seja, o servidor lança a Resposta Não Autorizada. Após essa resposta UnAuthorized Rest-Assured envia outra solicitação para o servidor que é o Auth.

given (). auth (). basic ("uNome", "pwd"). when (). get ("URL"). then (). statusCode (200);

Autenticação Digest

A partir de agora, apenas “autenticação digest desafiada” está sendo considerada. por exemplo:

given (). auth (). digest ("uName", "pwd"). when (). get ("URL"). then (). statusCode (200); 

Autenticação de Formulário

Poderíamos conseguir isso principalmente em 3 abordagens diferentes, dependendo do aplicativo / cenários:

A autenticação de formulário é uma das muito populares na Internet, em que um usuário insere suas credenciais, ou seja, nome de usuário e senha por meio de uma página da web e faz login no sistema. Isso pode ser resolvido usando este 

dado (). auth (). form ("uNome", "pWd").
when (). get ("URL");
then (). statusCode (200);

Embora isso possa não funcionar, pois é ideal e pode passar ou falhar dependendo da complexidade da página da web. A melhor opção é fornecer esses detalhes ao configurar a autenticação do formulário na abordagem abaixo:

given (). auth (). form ("uName", "pwd", new FormAuthConfig ("/ 'mencione aqui o nome da ação do formulário que faz parte do código da página html na tag do formulário'", "uName", "pwd ")). when (). get (" URL "). then (). statusCode (200);

Nesta abordagem, o REST Assured internamente não exigirá acionar solicitações adicionais e analisar a página da web. 

Se no caso de você estiver usando o padrão Spring Security, então um FormAuthConfig predefinido é acionado.

dado (). auth (). form ("uNome", "Pwd", FormAuthConfig.springSecurity ()). when (). get ("URL"). then (). statusCode (200);

NOTA: Se quisermos enviar dados de entrada adicionais junto com a autenticação do formulário, podemos escrever o seguinte:

dado (). auth (). form ("uNome", "pwd", formAuthConfig (). withAdditionalFields ("firstInputField", "secondInputField"). ..

CSRF:

CSRF significa falsificação de solicitação entre sites.

Hoje em dia é muito comum o servidor fornecer um token CSRF com a resposta para evitar os ataques de segurança do CSRF. REST Assured suporta isso usando um analisador automático e fornecendo token CSRF. 

Para atingir este REST Assured é necessário fazer um pedido adicional e analisar (poucas posições) do site.

Podemos habilitar o suporte CSRF escrevendo o código abaixo:

given (). auth (). form ("uNome", "pwd", formAuthConfig (). withAutoDetectionOfCsrf ()). when (). get ("URL"). then (). statusCode (200);

Além disso, para ajudar REST Assured e tornar a análise mais perfeita e robusta, podemos fornecer o nome do campo CSRF (aqui, assumindo que estamos usando os valores padrão do Spring Security e poderíamos usar o springSecurity FormAuthConfig predefinido):

given (). auth (). form ("uName", "pwd", springSecurity (). withCsrfFieldName ("_ csrf")). when (). get ("URL"). then (). statusCode (200);

Por padrão, o valor CSRF é passado como um parâmetro de formulário com a solicitação, mas podemos configurar para enviá-lo como um cabeçalho se for necessário, como abaixo:

given (). auth (). form ("uName", "pwd", springSecurity (). withCsrfFieldName ("_ csrf"). sendCsrfTokenAsHeader ()). when (). get ("URL"). then (). statusCode (200);

OAuth 1:

OAuth 1 requer que o Scribe esteja no caminho de classe. Para usar a autenticação oAuth 1, podemos fazer:

dado (). auth (). oauth (..). quando (). ..

OAuth 2:

dado (). auth (). oauth2 (accessToken) .when (). ..

Na abordagem acima, o accessToken OAuth2 será considerado em um cabeçalho. Para ser mais explícito, também podemos fazer:

given (). auth (). preemptive (). oauth2 (accessToken) .when (). ..

Passando arquivo, matriz de bytes, fluxo de entrada ou texto na solicitação:

Ao enviar grandes quantidades de dados para o servidor, geralmente é uma abordagem comum usar a técnica de dados de formulário multipartes. Rest Assured fornece métodos chamados multiPart que nos permitem especificar um arquivo, byte-array, fluxo de entrada ou texto para upload. 

given (). multiPart (new File ("/ File_Path")). when (). post ("/ upload");

Criação de solicitação POST com descanso garantido

Com as solicitações POST e PUT, enviamos Dados para o Servidor e sua basicamente criação / atualização de recursos, pode-se considerar isso como uma operação de gravação ou atualização.

Os dados que estão sendo enviados ao servidor em uma solicitação POST são enviados no corpo da solicitação HTTP / chamada API. 

O tipo de conteúdo ou dados que está sendo enviado pode ser de formato diferente dependendo da API, ou seja, XML, JSON ou algum outro formato é definido pelo cabeçalho Content-Type. 

Se o corpo POST consistir em dados JSON, o cabeçalho Content-Type será application / json. Da mesma forma, para uma solicitação POST consistindo em um XML, o cabeçalho Content-Type seria do tipo application / xml.

Aqui está o snippet de código abaixo para o mesmo:

given (). contentType ("application / json"). param ("pk", "pv"). when (). body ("JsonPAyloadString"). post ("url"). then (). assertThat (). statusCode (200);

NOTA: Existem diferentes maneiras de passar o corpo da carga / solicitação dentro do método "corpo", como String (conforme mostrado no trecho acima), JsonObject, como um arquivo etc etc,

Solicitação PUT com a certeza:

given (). contentType ("application / json"). param ("pk", "pv"). when (). body ("JsonPAyloadString"). put ("url"). then (). assertThat (). statusCode (200);

Excluir solicitação com Rest-Assured:

given (). contentType ("application / json"). param ("pk", "pv"). when (). delete ("url"). then (). assertThat (). statusCode (200);

E, dessa forma, podemos criar diferentes chamadas de API Rest para diferentes verbos de API (GET / POST / PUT / DELETE etc)

Serialização e desserialização em Java:

A serialização é basicamente um processamento ou conversão do estado do objeto em um fluxo de bytes. Por outro lado, a desserialização em Java está processando ou convertendo o fluxo de bytes em um objeto Java real dentro da memória. Este mecanismo é usado na persistência do objeto.

Abaixo está o diagrama de blocos para o mesmo 

1ESLuGPTk5gUs9eA5 OXkbw KyHeRnO9TdX bg OEo3 ZD7BJ9HqLY HcOaf9saeK137JSzmDj7 TY2WmrlVogzLzkgmN1gvLvyaF6cdGb6psTcv0HVH98J45L4b1a0c3ucUvJ6p

Vantagens da serialização

A. Para salvar / persistir o estado de um objeto.

B. Para fazer um objeto fluir em uma rede.

Atingindo a serialização com JAVA

Para obter um objeto Java serializável, precisamos implementar a interface java.io.Serializable.

A classe ObjectOutputStream que contém o método writeObject () responsável por serializar um Object.

A classe ObjectInputStream também contém outro método chamado readObject (), que é responsável por desserializar um objeto.

classes que estão implementando a interface java.io.Serializable, seu objeto só pode ser serializado.

Serializable é apenas uma interface de marcador e, como outra interface de mercado, não tem nenhum membro de dados ou método associado a ela. Que é usada para “marcar” classes java de modo que os objetos dessas classes obtenham determinados recursos. Como algumas outras interfaces de marcador são: - Clonável e Remoto, etc.

Notas :

1. Se uma classe pai implementou uma interface serializável, então a classe filha não é necessária para implementar a mesma, mas vice-versa não é aplicável.

2. Apenas membros de dados não estáticos são armazenados com o processo de serialização.

3. Os membros de dados estáticos e também os membros de dados transientes não estão sendo armazenados pela serialização. Portanto, no caso de não precisarmos armazenar o valor do membro de dados não estáticos, podemos torná-lo transiente.

4. O construtor nunca é chamado quando um objeto é desserializado.

ETAPA 1: A primeira etapa é basicamente a criação de uma classe que implementa a interface serializável:

importar java.io.Serializable;
public class Dummy implementa Serializable {
    int privado i;
    dados de string privados;
    public Dummy (int i, String data)
    {
        este.i = i;
        this.data = data;
    }
}

ETAPA 2: crie uma classe para serializá-la:

importar java.io.FileNotFoundException;
importar java.io.FileOutputStream;
import java.io.IOException;
importar java.io.ObjectOutputStream;
public class Serialize {
    public static void Serialization (Object classObject, String fileName) {
        experimentar {
            FileOutputStream fileStream = new FileOutputStream (fileName);
            ObjectOutputStream objectStream = new ObjectOutputStream (fileStream);
            objectStream.writeObject (classObject);
            objectStream.close ();
            fileStream.close ();
        } catch (FileNotFoundException e) {
            // TODO bloco de captura gerado automaticamente
            e.printStackTrace ();
        } catch(IOException e) {
            // TODO bloco de captura gerado automaticamente
            e.printStackTrace ();
        }
    }
    main (String [] args) public static void {
        Dummy dummyObj = novo Dummy (10, "Lambda-geeks");
        Serialização (dummyObj, "DummSerialized");
    }
}

ETAPA 3: Depois que a Etapa 2 for concluída com êxito, você verá um arquivo criado com alguns dados, esses dados são basicamente dados serializados dos membros do Objeto.

  Desserialização com java:

Aqui está o snippet de código abaixo:

 public static Object DeSerialize (String fileName)
    {
        experimentar {
            FileInputStream fileStream = new FileInputStream (new File (fileName));
            ObjectInputStream objectStream = new ObjectInputStream (fileStream);
            Object deserializeObject = objectStream.readObject ();
            objectStream.close ();
            fileStream.close ();
            return desserializeObject;
        } catch (FileNotFoundException e) {
            e.printStackTrace ();
        } catch(IOException e) {
            e.printStackTrace ();
        } catch (ClassNotFoundException e) {
            e.printStackTrace ();
        }
        retornar nulo;
    }

O código do driver é assim:

 main (String [] args) public static void {
      / * Dummy dummyObj = novo Dummy (10, "Lambda-geeks");
        Serialização (dummyObj, "DummSerialized");
        System.out.println ("------------------------------------------- ------------------------------- ");
      */
        Dummy deSerializedRect = (Dummy) DeSerialize ("DummSerialized");
        System.out.println ("Dados do objeto serializado" + deSerializedRect.print ());
        System.out.println ("------------------------------------------- ------------------------------- ");
    }

JSONPATH Mais sintaxe / consulta:

Vamos supor um JSON conforme abaixo:

{
  "OrganizationDetails": "Dummy Details of the Organization",
  "Região": "Ásia",
  "Emp-Details": [
    {
      "Org": "lambda-Geeks",
      "Em formação": {
        "Ph": 1234567890,
        "Adicionar": "XYZ",
        "Idade": 45
      }
    },
    {
      "Org": "lambda-Geeks-2",
      "Em formação": {
        "Ph": 2134561230,
        "Adicionar": "ABC",
        "Idade": 35
      }
    }
  ]
}

no JSON acima, o OrganizationDetails & Region são chamados de Nó Folha, sendo que eles não estão tendo nenhum outro nó / elemento filho, mas por outro lado o Emp-Details tem um nó filho, portanto, não é referido como Nó Folha.

Aqui, se tentarmos obter o valor de OrganizationDetails, precisamos usar:

$ .OrganizationDetails 
Isso resultará em:
 [
  "Detalhes Fictícios da Organização"
]

Like Wise para obter os dados da região que precisamos escrever:

$ .Region 

Se quisermos encontrar o valor da Idade para o 1º Funcionário, podemos escrever:

$ .Emp-Detalhes [0] .Information.Age
Isso resultará em:
[
  45
]

Para a Idade do 2º Funcionário, poderíamos escrever como

$ .Emp-Detalhes [1] .Information.Age
Isso resultará em: [35]

Dessa forma, podemos descobrir a expressão / consulta JsonPath para buscar os dados para os respectivos campos no JSON.