SlideShare uma empresa Scribd logo
1 de 53
Baixar para ler offline
Automação e Virtualização de
serviços REST com
RestAssured + Wiremock + Docker
@eliasnogueira
Passos...
1 Entender a documentação da API
2 Pensar nos testes com uma divisão de pipeline
3 Criar uma versão inicial da arquitetura
4 Criar os testes e definir as suítes de testes
5 Criar mocks para resolver problemas
* massa de dados, dependências, indisponibilidades
API do TDC
https://www.globalcode.com.br/api
Expõe a API de consulta a:
§ Eventos
§ Modalidades
§ Coordenadores
§ Palestrantes
§ Palestras
Através de um ClientID e um
Secret é gerado um
Access-Token em OAuth2
Possui a documentação via
OpenAPI para download na
própria página de acesso
1.
Entender a
documentação da API
Entender os controllers
§ operações
§ endpoints
§ parâmetros de entrada
§ saída
§ autenticação
2.
Pensar nos testes com
uma divisão de
pipeline
API
Pipeline
Health Check
Contrato
Funcional
Aceitação
Garantir que o endpoint está respondendo
HTTP 200
Garantir que o endpoint não teve seus
atributos alterados
Garantir que o endpoint funciona ou apresenta
os resultados de falha esperados
Garantir que um conjunto de endpoints
funcionam como na UI
3.
Criar uma versão
inicial da arquitetura
Arquitetura
src test
Geração do Access Token
necessário para a execução
dos testes
Leitor de Configurações
para ler, ao menos, os
dados de autenticação
beans e builders
suportar melhor a escrita
dos testes
BaseTest
para remover a duplicidade
de pré-condição
json schemas
schemas dos recursos para
o teste de contrato
Suítes de Teste
habilitará a rápida
execução de testes
4.
Criar testes e definir as
suítes de teste
Rest-Assured
http://rest-assured.io
DSL Java para testar e validar APIs REST.
import static io.restassured.RestAssured.*;
import static org.hamcrest.Matchers.*;
public class ExemploRestAssured {
@Test
public void boasVindas() {
given().
param("nome", "Elias").
when().
post("/cadastro").
then().
body("mensagem", is("Olá Elias"));
}
}
Rest-Assured
http://rest-assured.io
DSL Java para testar e validar APIs REST.
import static io.restassured.RestAssured.*;
import static org.hamcrest.Matchers.*;
public class ExemploRestAssured {
@Test
public void boasVindas() {
given().
param("nome", "Elias").
when().
post("/cadastro").
then().
body("mensagem", is("Olá Elias"));
}
}
importação das
bibliotecas necessárias
Rest-Assured
http://rest-assured.io
DSL Java para testar e validar APIs REST.
import static io.restassured.RestAssured.*;
import static org.hamcrest.Matchers.*;
public class ExemploRestAssured {
@Test
public void boasVindas() {
given().
param("nome", "Elias").
when().
post("/cadastro").
then().
body("mensagem", is("Olá Elias"));
}
}
pré-condição para a
requisição
Rest-Assured
http://rest-assured.io
DSL Java para testar e validar APIs REST.
import static io.restassured.RestAssured.*;
import static org.hamcrest.Matchers.*;
public class ExemploRestAssured {
@Test
public void boasVindas() {
given().
param("nome", "Elias").
when().
post("/cadastro").
then().
body("mensagem", is("Olá Elias"));
}
}
ação (requisição)
Rest-Assured
http://rest-assured.io
DSL Java para testar e validar APIs REST.
import static io.restassured.RestAssured.*;
import static org.hamcrest.Matchers.*;
public class ExemploRestAssured {
@Test
public void boasVindas() {
given().
param("nome", "Elias").
when().
post("/cadastro").
then().
body("mensagem", is("Olá Elias"));
}
}
validação dos dados
de retorno
Gerar do Access-Token
public String getAccessToken() {
Configuration configuration = new Configuration();
String username = configuration.getAuthenticationUsername();
String password = configuration.getAuthenticationPassword();
baseURI = configuration.getAPIURL();
basePath = configuration.getAPIOauthContext();
return
given().
auth()
.preemptive().basic(username, password).
when().
get("/").
then().
extract().
path("Access-Token");
}
Gerar do Access-Token
public String getAccessToken() {
Configuration configuration = new Configuration();
String username = configuration.getAuthenticationUsername();
String password = configuration.getAuthenticationPassword();
baseURI = configuration.getAPIURL();
basePath = configuration.getAPIOauthContext();
return
given().
auth()
.preemptive().basic(username, password).
when().
get("/").
then().
extract().
path("Access-Token");
}
a autenticação é enviada
como pré-condição
Gerar do Access-Token
public String getAccessToken() {
Configuration configuration = new Configuration();
String username = configuration.getAuthenticationUsername();
String password = configuration.getAuthenticationPassword();
baseURI = configuration.getAPIURL();
basePath = configuration.getAPIOauthContext();
return
given().
auth()
.preemptive().basic(username, password).
when().
get("/").
then().
extract().
path("Access-Token");
}
access-token é
retornado como
String
Leitor de Configurações
public String getAccessToken() {
Configuration configuration = new Configuration();
String username = configuration.getAuthenticationUsername();
String password = configuration.getAuthenticationPassword();
baseURI = configuration.getAPIURL();
basePath = configuration.getAPIOauthContext();
return
given().
auth()
.preemptive().basic(username, password).
when().
get("/").
then().
extract().
path("Access-Token");
}
lê dados de
autenticação
Leitor de Configurações
public String getAccessToken() {
Configuration configuration = new Configuration();
String username = configuration.getAuthenticationUsername();
String password = configuration.getAuthenticationPassword();
baseURI = configuration.getAPIURL();
basePath = configuration.getAPIOauthContext();
return
given().
auth()
.preemptive().basic(username, password).
when().
get("/").
then().
extract().
path("Access-Token");
}
lê dados para
acesso ao token
BaseTest
public abstract class BaseTest {
protected static String accessToken;
@BeforeClass(alwaysRun = true)
public static void beforeClass() {
Configuration configuration = new Configuration();
accessToken = new GenerateAccessToken().
getAccessToken();
baseURI = configuration.getAPIURL();
basePath = configuration.getPublico();
}
}
Código executado antes de cada teste
BaseTest
public abstract class BaseTest {
protected static String accessToken;
@BeforeClass(alwaysRun = true)
public static void beforeClass() {
Configuration configuration = new Configuration();
accessToken = new GenerateAccessToken().
getAccessToken();
baseURI = configuration.getAPIURL();
basePath = configuration.getPublico();
}
}
Código executado antes de cada teste
accessToken que
será acessado pelas
classes de teste
BaseTest
public abstract class BaseTest {
protected static String accessToken;
@BeforeClass(alwaysRun = true)
public static void beforeClass() {
Configuration configuration = new Configuration();
accessToken = new GenerateAccessToken().
getAccessToken();
baseURI = configuration.getAPIURL();
basePath = configuration.getPublico();
}
}
Código executado antes de cada teste
gera o accessToken
apenas uma vez para
a execução de teste
BaseTest
public abstract class BaseTest {
protected static String accessToken;
@BeforeClass(alwaysRun = true)
public static void beforeClass() {
Configuration configuration = new Configuration();
accessToken = new GenerateAccessToken().
getAccessToken();
baseURI = configuration.getAPIURL();
basePath = configuration.getPublico();
}
}
Código executado antes de cada teste
chamada da classe
de geração do token
BaseTest
public abstract class BaseTest {
protected static String accessToken;
@BeforeClass(alwaysRun = true)
public static void beforeClass() {
Configuration configuration = new Configuration();
accessToken = new GenerateAccessToken().
getAccessToken();
baseURI = configuration.getAPIURL();
basePath = configuration.getPublico();
}
}
Código executado antes de cada teste
necessário informar
novamente o
apontamento da API
* porque já foi apontado na geração do access token
health-check
Garantir que o endpoint está
respondendo
heath-check
Apenas validamos se o statuscode é 200
public class EventoDetalheTest extends BaseTest {
@Test(groups = { "health" })
public void healthCheck() {
given().
auth().oauth2(accessToken).
when().
get("evento/{id}", id).
then().
statusCode(HttpStatus.SC_OK);
}
heath-check
Apenas validamos se o statuscode é 200
tag de grupo para
filtrar a execução
public class EventoDetalheTest extends BaseTest {
@Test(groups = { "health" })
public void healthCheck() {
given().
auth().oauth2(accessToken).
when().
get("evento/{id}", id).
then().
statusCode(HttpStatus.SC_OK);
}
heath-check
Apenas validamos se o statuscode é 200
public class EventoDetalheTest extends BaseTest {
@Test(groups = { "health" })
public void healthCheck() {
given().
auth().oauth2(accessToken).
when().
get("evento/{id}", id).
then().
statusCode(HttpStatus.SC_OK);
}
inserir sempre o access-token
como pré-condição da requisição
heath-check
Apenas validamos se o statuscode é 200
public class EventoDetalheTest extends BaseTest {
@Test(groups = { "health" })
public void healthCheck() {
given().
auth().oauth2(accessToken).
when().
get("evento/{id}", id).
then().
statusCode(HttpStatus.SC_OK);
}
validar se o status code,
e somente ele, é 200
contrato
Garantir que o endpoint não teve
seus atributos alterados
● É o nome dado ao pacto entre o produtor e consumidor
● Garante que mudanças na API não invalidem o consumo:
● path
● parâmetros
● dados de envio (request)
● dados de retorno (response body)
● json-schema é um contrato que define os dados
esperados, tipos e formatos de cada campo na resposta
contrato
{
"nome": "Elias",
"idade": 36
}
{
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"properties": {
"nome": {
"type": "string"
},
"idade": {
"type": "integer"
}
},
"required": [
"nome",
"idade"
],
"additionalProperties": false
}
json-schema
{
"nome": "Elias",
"idade": 36
}
{
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"properties": {
"nome": {
"type": "string"
},
"idade": {
"type": "integer"
}
},
"required": [
"nome",
"idade"
],
"additionalProperties": false
}
json-schema possui o nome
do atributo e o tipo de dados
json-schema
{
"nome": "Elias",
"idade": 36
}
{
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"properties": {
"nome": {
"type": "string"
},
"idade": {
"type": "integer"
}
},
"required": [
"nome",
"idade"
],
"additionalProperties": false
}
os dois atributos devem estar
presentes, obrigatoriamente
json-schema
{
"nome": "Elias",
"idade": 36
}
{
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"properties": {
"nome": {
"type": "string"
},
"idade": {
"type": "integer"
}
},
"required": [
"nome",
"idade"
],
"additionalProperties": false
}
json-schema
nenhum outro
atributo é permitido
teste funcional
na minha máquina funciona
¯_(ツ)_/¯
funcional
Validar cenários positivos e negativos (caminho feliz | fluxo exceção)
@Test(groups = {"funcional"})
public void validarEventoPeloID() {
given().
auth().oauth2(accessToken).
when().
get("evento/{id}", 110).
then().
statusCode(HttpStatus.SC_OK).
body("[0].id", is(110)).
body("[0].descricao", is("TDC 2019 Florianópolis")).
body("[0].chave", is("tdc-2019-florianopolis")).
body("[0].ativo", is(true)).
body("[0].dias", is(5)).
body("[0].dataInicio", is("2019-04-23 00:00:00")).
body("[0].dataTermino", is("2019-04-27 00:00:00"));
}
funcional
Validar cenários positivos e negativos (caminho feliz | fluxo exceção)
@Test(groups = {"funcional"})
public void validarEventoPeloID() {
given().
auth().oauth2(accessToken).
when().
get("evento/{id}", 110).
then().
statusCode(HttpStatus.SC_OK).
body("[0].id", is(110)).
body("[0].descricao", is("TDC 2019 Florianópolis")).
body("[0].chave", is("tdc-2019-florianopolis")).
body("[0].ativo", is(true)).
body("[0].dias", is(5)).
body("[0].dataInicio", is("2019-04-23 00:00:00")).
body("[0].dataTermino", is("2019-04-27 00:00:00"));
}
tag de grupo para
filtrar a execução
funcional
Validar cenários positivos e negativos (caminho feliz | fluxo exceção)
@Test(groups = {"funcional"})
public void validarEventoPeloID() {
given().
auth().oauth2(accessToken).
when().
get("evento/{id}", 110).
then().
statusCode(HttpStatus.SC_OK).
body("[0].id", is(110)).
body("[0].descricao", is("TDC 2019 Florianópolis")).
body("[0].chave", is("tdc-2019-florianopolis")).
body("[0].ativo", is(true)).
body("[0].dias", is(5)).
body("[0].dataInicio", is("2019-04-23 00:00:00")).
body("[0].dataTermino", is("2019-04-27 00:00:00"));
}
requisição para obter
o detalhe de um
determinado evento
funcional
Validar cenários positivos e negativos (caminho feliz | fluxo exceção)
@Test(groups = {"funcional"})
public void validarEventoPeloID() {
given().
auth().oauth2(accessToken).
when().
get("evento/{id}", 110).
then().
statusCode(HttpStatus.SC_OK).
body("[0].id", is(110)).
body("[0].descricao", is("TDC 2019 Florianópolis")).
body("[0].chave", is("tdc-2019-florianopolis")).
body("[0].ativo", is(true)).
body("[0].dias", is(5)).
body("[0].dataInicio", is("2019-04-23 00:00:00")).
body("[0].dataTermino", is("2019-04-27 00:00:00"));
}
validação dos dados
de retorno (body)
* [0] existe ali porque o retorno é um array de uma posição
* é um possível bug da implementação
aceitação
Garantir que um conjunto de endpoints
funcionam como na UI
Testar com a perspectiva do usuário
● Entrar no evento The Developers Conference Florianópolis
● Clicar na Trilha DevTest
● Visualizar os detalhes da palestra Automação e
Virtualização de serviços REST com RestAssured +
Wiremock + Docker
aceitação
@Test(groups = {"aceitacao"})
public void visualizaDetalhes_EncontrandoDados() throws ObjetoNotFoundException {
String tituloPalestra = "Automação e Virtualização de serviços REST ";
Evento evento = encontraEvento("TDC 2019 Florianópolis");
Modalidade trilha = encontraTrilha(evento, "Trilha DevTest");
Palestra palestra = encontraPalestra(evento, trilha, tituloPalestra);
given().
auth().
oauth2(accessToken).
pathParam("eventoID", evento.getId()).
pathParam("modalidadeID", trilha.getId()).
pathParam("palestraID", palestra.getId()).
when().
get("/evento/{eventoID}/modalidade/{modalidadeID}/palestra/{palestraID}/palestrantes").
then().
statusCode(200).
body("[0].member.nome", is("Elias Nogueira")).
body("[0].member.empresa", is("Sicredi"));
}
aceitação
@Test(groups = {"aceitacao"})
public void visualizaDetalhes_EncontrandoDados() throws ObjetoNotFoundException {
String tituloPalestra = "Automação e Virtualização de serviços REST ";
Evento evento = encontraEvento("TDC 2019 Florianópolis");
Modalidade trilha = encontraTrilha(evento, "Trilha DevTest");
Palestra palestra = encontraPalestra(evento, trilha, tituloPalestra);
given().
auth().
oauth2(accessToken).
pathParam("eventoID", evento.getId()).
pathParam("modalidadeID", trilha.getId()).
pathParam("palestraID", palestra.getId()).
when().
get("/evento/{eventoID}/modalidade/{modalidadeID}/palestra/{palestraID}/palestrantes").
then().
statusCode(200).
body("[0].member.nome", is("Elias Nogueira")).
body("[0].member.empresa", is("Sicredi"));
}
funções auxiliares para chamadas a
cada ação do usuário
aceitação
@Test(groups = {"aceitacao"})
public void visualizaDetalhes_EncontrandoDados() throws ObjetoNotFoundException {
String tituloPalestra = "Automação e Virtualização de serviços REST ";
Evento evento = encontraEvento("TDC 2019 Florianópolis");
Modalidade trilha = encontraTrilha(evento, "Trilha DevTest");
Palestra palestra = encontraPalestra(evento, trilha, tituloPalestra);
given().
auth().
oauth2(accessToken).
pathParam("eventoID", evento.getId()).
pathParam("modalidadeID", trilha.getId()).
pathParam("palestraID", palestra.getId()).
when().
get("/evento/{eventoID}/modalidade/{modalidadeID}/palestra/{palestraID}/palestrantes").
then().
statusCode(200).
body("[0].member.nome", is("Elias Nogueira")).
body("[0].member.empresa", is("Sicredi"));
}
uso dos dados obtidos
para a requisição
service virtualization
disponibilizar mocks de seviços
● Forma de simular comportamentos de componentes
baseados em API
● Habilita o uso de serviços virtuais ao invés de serviços de
produção mesmo que componentes chave não estejam
disponíveis
service virtualization
service virtualization
{
"id" : "f238845e-369c-4a34-aa69-04d9240d7fb5",
"name" : "evento_modalidade_palestra",
"request" : {
"urlPattern" : "/v1/publico/evento/110/modalidade/2685/palestra/10083",
"method" : "GET"
},
"response" : {
"status" : 200,
"bodyFileName" : "evento_modalidade_palestra_data.json",
"headers" : {
"Authorization": "*"
}
},
"persistent" : true,
"insertionIndex" : 1
}
service virtualization
{
"id" : "f238845e-369c-4a34-aa69-04d9240d7fb5",
"name" : "evento_modalidade_palestra",
"request" : {
"urlPattern" : "/v1/publico/evento/110/modalidade/2685/palestra/10083",
"method" : "GET"
},
"response" : {
"status" : 200,
"bodyFileName" : "evento_modalidade_palestra_data.json",
"headers" : {
"Authorization": "*"
}
},
"persistent" : true,
"insertionIndex" : 1
}
sempre que uma requisição for igual a esta
URL (inclusive com os dados)
service virtualization
{
"id" : "f238845e-369c-4a34-aa69-04d9240d7fb5",
"name" : "evento_modalidade_palestra",
"request" : {
"urlPattern" : "/v1/publico/evento/110/modalidade/2685/palestra/10083",
"method" : "GET"
},
"response" : {
"status" : 200,
"bodyFileName" : "evento_modalidade_palestra_data.json",
},
"persistent" : true,
"insertionIndex" : 1
}
a api responderá os dados abaixo...
service virtualization
{
"id": 10083,
"slot": 6,
"ordem": 1,
"titulo": "Automação e Virtualização de serviços REST...",
"descricao": ”Você sempre quis aprender a como testar...",
"tipo": 2,
"horario": "16:40"
}
dados de retorno
@eliasnogueira
github.com/eliasnogueira
Obrigado!

Mais conteúdo relacionado

Mais procurados

RESTful API Testing using Postman, Newman, and Jenkins
RESTful API Testing using Postman, Newman, and JenkinsRESTful API Testing using Postman, Newman, and Jenkins
RESTful API Testing using Postman, Newman, and JenkinsQASymphony
 
An Introduction To Automated API Testing
An Introduction To Automated API TestingAn Introduction To Automated API Testing
An Introduction To Automated API TestingSauce Labs
 
API Test Automation
API Test Automation API Test Automation
API Test Automation SQALab
 
API Testing: The heart of functional testing" with Bj Rollison
API Testing: The heart of functional testing" with Bj RollisonAPI Testing: The heart of functional testing" with Bj Rollison
API Testing: The heart of functional testing" with Bj RollisonTEST Huddle
 
Test your microservices with REST-Assured
Test your microservices with REST-AssuredTest your microservices with REST-Assured
Test your microservices with REST-AssuredMichel Schudel
 
Karate, the black belt of HTTP API testing?
Karate, the black belt of HTTP API testing?Karate, the black belt of HTTP API testing?
Karate, the black belt of HTTP API testing?Bertrand Delacretaz
 
Usando containers com auto-escala de testes
Usando containers com auto-escala de testesUsando containers com auto-escala de testes
Usando containers com auto-escala de testesElias Nogueira
 
API Testing following the Test Pyramid
API Testing following the Test PyramidAPI Testing following the Test Pyramid
API Testing following the Test PyramidElias Nogueira
 
TDC2015: Testes em APIs REST com Rest-Assured
TDC2015: Testes em APIs REST com Rest-AssuredTDC2015: Testes em APIs REST com Rest-Assured
TDC2015: Testes em APIs REST com Rest-AssuredJúlio de Lima
 
API Test Automation Using Karate (Anil Kumar Moka)
API Test Automation Using Karate (Anil Kumar Moka)API Test Automation Using Karate (Anil Kumar Moka)
API Test Automation Using Karate (Anil Kumar Moka)Peter Thomas
 
Testes E2E em Cypress com JS
Testes E2E em Cypress com JSTestes E2E em Cypress com JS
Testes E2E em Cypress com JSNàtali Cabral
 
B4USolution_API-Testing
B4USolution_API-TestingB4USolution_API-Testing
B4USolution_API-Testingb4usolution .
 
Papel do QA na Transformação Ágil
Papel do QA na Transformação ÁgilPapel do QA na Transformação Ágil
Papel do QA na Transformação ÁgilElias Nogueira
 
Ppt of soap ui
Ppt of soap uiPpt of soap ui
Ppt of soap uipkslide28
 

Mais procurados (20)

Rest assured
Rest assuredRest assured
Rest assured
 
RESTful API Testing using Postman, Newman, and Jenkins
RESTful API Testing using Postman, Newman, and JenkinsRESTful API Testing using Postman, Newman, and Jenkins
RESTful API Testing using Postman, Newman, and Jenkins
 
An Introduction To Automated API Testing
An Introduction To Automated API TestingAn Introduction To Automated API Testing
An Introduction To Automated API Testing
 
API Test Automation
API Test Automation API Test Automation
API Test Automation
 
API Testing: The heart of functional testing" with Bj Rollison
API Testing: The heart of functional testing" with Bj RollisonAPI Testing: The heart of functional testing" with Bj Rollison
API Testing: The heart of functional testing" with Bj Rollison
 
API Testing for everyone.pptx
API Testing for everyone.pptxAPI Testing for everyone.pptx
API Testing for everyone.pptx
 
Test your microservices with REST-Assured
Test your microservices with REST-AssuredTest your microservices with REST-Assured
Test your microservices with REST-Assured
 
Karate, the black belt of HTTP API testing?
Karate, the black belt of HTTP API testing?Karate, the black belt of HTTP API testing?
Karate, the black belt of HTTP API testing?
 
Usando containers com auto-escala de testes
Usando containers com auto-escala de testesUsando containers com auto-escala de testes
Usando containers com auto-escala de testes
 
API Testing following the Test Pyramid
API Testing following the Test PyramidAPI Testing following the Test Pyramid
API Testing following the Test Pyramid
 
API Docs with OpenAPI 3.0
API Docs with OpenAPI 3.0API Docs with OpenAPI 3.0
API Docs with OpenAPI 3.0
 
TDC2015: Testes em APIs REST com Rest-Assured
TDC2015: Testes em APIs REST com Rest-AssuredTDC2015: Testes em APIs REST com Rest-Assured
TDC2015: Testes em APIs REST com Rest-Assured
 
Postman
PostmanPostman
Postman
 
Api testing
Api testingApi testing
Api testing
 
API Test Automation Using Karate (Anil Kumar Moka)
API Test Automation Using Karate (Anil Kumar Moka)API Test Automation Using Karate (Anil Kumar Moka)
API Test Automation Using Karate (Anil Kumar Moka)
 
Rest assured
Rest assuredRest assured
Rest assured
 
Testes E2E em Cypress com JS
Testes E2E em Cypress com JSTestes E2E em Cypress com JS
Testes E2E em Cypress com JS
 
B4USolution_API-Testing
B4USolution_API-TestingB4USolution_API-Testing
B4USolution_API-Testing
 
Papel do QA na Transformação Ágil
Papel do QA na Transformação ÁgilPapel do QA na Transformação Ágil
Papel do QA na Transformação Ágil
 
Ppt of soap ui
Ppt of soap uiPpt of soap ui
Ppt of soap ui
 

Semelhante a Automação e virtualização de serviços

TDD - Algumas lições aprendidas com o livro GOOS
TDD - Algumas lições aprendidas com o livro GOOSTDD - Algumas lições aprendidas com o livro GOOS
TDD - Algumas lições aprendidas com o livro GOOSFábio Miranda
 
Play Framework - FLISOL
Play Framework - FLISOLPlay Framework - FLISOL
Play Framework - FLISOLgrupoweblovers
 
Workshop Microservices - Construindo APIs RESTful com Spring Boot
Workshop Microservices - Construindo APIs RESTful com Spring BootWorkshop Microservices - Construindo APIs RESTful com Spring Boot
Workshop Microservices - Construindo APIs RESTful com Spring BootRodrigo Cândido da Silva
 
PDC - Engenharia - Plataforma Microsoft .NET
PDC - Engenharia - Plataforma Microsoft .NETPDC - Engenharia - Plataforma Microsoft .NET
PDC - Engenharia - Plataforma Microsoft .NETslides_teltools
 
Ecosistema spring a_plataforma_enterprise_jav
Ecosistema spring a_plataforma_enterprise_javEcosistema spring a_plataforma_enterprise_jav
Ecosistema spring a_plataforma_enterprise_javJulio Viegas
 
CDI Extensions e DeltaSpike
CDI Extensions e DeltaSpikeCDI Extensions e DeltaSpike
CDI Extensions e DeltaSpikeRafael Benevides
 
AspectJ — Programação orientada a aspectos em Java
AspectJ — Programação orientada a aspectos em JavaAspectJ — Programação orientada a aspectos em Java
AspectJ — Programação orientada a aspectos em Javaelliando dias
 
JavaOne LATAM 2016 - Combinando AngularJS com Java EE
JavaOne LATAM 2016 - Combinando AngularJS com Java EEJavaOne LATAM 2016 - Combinando AngularJS com Java EE
JavaOne LATAM 2016 - Combinando AngularJS com Java EERodrigo Cândido da Silva
 
Como conectar programas em linguagem java a bases de dados
Como conectar programas em linguagem java  a bases de dadosComo conectar programas em linguagem java  a bases de dados
Como conectar programas em linguagem java a bases de dadosHenrique Fernandes
 
Teste de Integracao com DbUnit e JStryker
Teste de Integracao com DbUnit e JStrykerTeste de Integracao com DbUnit e JStryker
Teste de Integracao com DbUnit e JStrykerWashington Botelho
 
Automação de Teste para REST, Web e Mobile
Automação de Teste para REST, Web e MobileAutomação de Teste para REST, Web e Mobile
Automação de Teste para REST, Web e MobileElias Nogueira
 

Semelhante a Automação e virtualização de serviços (20)

TDD - Algumas lições aprendidas com o livro GOOS
TDD - Algumas lições aprendidas com o livro GOOSTDD - Algumas lições aprendidas com o livro GOOS
TDD - Algumas lições aprendidas com o livro GOOS
 
Play Framework - FLISOL
Play Framework - FLISOLPlay Framework - FLISOL
Play Framework - FLISOL
 
Vraptor
VraptorVraptor
Vraptor
 
Workshop Microservices - Construindo APIs RESTful com Spring Boot
Workshop Microservices - Construindo APIs RESTful com Spring BootWorkshop Microservices - Construindo APIs RESTful com Spring Boot
Workshop Microservices - Construindo APIs RESTful com Spring Boot
 
PDC - Engenharia - Plataforma Microsoft .NET
PDC - Engenharia - Plataforma Microsoft .NETPDC - Engenharia - Plataforma Microsoft .NET
PDC - Engenharia - Plataforma Microsoft .NET
 
Ecosistema spring a_plataforma_enterprise_jav
Ecosistema spring a_plataforma_enterprise_javEcosistema spring a_plataforma_enterprise_jav
Ecosistema spring a_plataforma_enterprise_jav
 
CDI Extensions e DeltaSpike
CDI Extensions e DeltaSpikeCDI Extensions e DeltaSpike
CDI Extensions e DeltaSpike
 
VRaptor4
VRaptor4VRaptor4
VRaptor4
 
Spring Capitulo 03
Spring Capitulo 03Spring Capitulo 03
Spring Capitulo 03
 
AspectJ — Programação orientada a aspectos em Java
AspectJ — Programação orientada a aspectos em JavaAspectJ — Programação orientada a aspectos em Java
AspectJ — Programação orientada a aspectos em Java
 
JavaOne LATAM 2016 - Combinando AngularJS com Java EE
JavaOne LATAM 2016 - Combinando AngularJS com Java EEJavaOne LATAM 2016 - Combinando AngularJS com Java EE
JavaOne LATAM 2016 - Combinando AngularJS com Java EE
 
Workshop05
Workshop05Workshop05
Workshop05
 
API Apontador
API ApontadorAPI Apontador
API Apontador
 
Design patterns
Design patternsDesign patterns
Design patterns
 
Como conectar programas em linguagem java a bases de dados
Como conectar programas em linguagem java  a bases de dadosComo conectar programas em linguagem java  a bases de dados
Como conectar programas em linguagem java a bases de dados
 
Wicket 2008
Wicket 2008Wicket 2008
Wicket 2008
 
Teste de Integracao com DbUnit e JStryker
Teste de Integracao com DbUnit e JStrykerTeste de Integracao com DbUnit e JStryker
Teste de Integracao com DbUnit e JStryker
 
Automação de Teste para REST, Web e Mobile
Automação de Teste para REST, Web e MobileAutomação de Teste para REST, Web e Mobile
Automação de Teste para REST, Web e Mobile
 
ASP.NET Web API
ASP.NET Web APIASP.NET Web API
ASP.NET Web API
 
Spring MVC - QConSP
Spring MVC - QConSPSpring MVC - QConSP
Spring MVC - QConSP
 

Mais de Elias Nogueira

Coach por Imersão - Buscando a excelência técnica com o time
Coach por Imersão - Buscando a excelência técnica com o timeCoach por Imersão - Buscando a excelência técnica com o time
Coach por Imersão - Buscando a excelência técnica com o timeElias Nogueira
 
O Agile Coach pode (e muitas vezes deve) ser técnico
O Agile Coach pode (e muitas vezes deve) ser técnicoO Agile Coach pode (e muitas vezes deve) ser técnico
O Agile Coach pode (e muitas vezes deve) ser técnicoElias Nogueira
 
Create an architecture for web test automation
Create an architecture for web test automationCreate an architecture for web test automation
Create an architecture for web test automationElias Nogueira
 
Paralelize seus testes web e mobile para ter feedbacks mais rápidos
Paralelize seus testes web e mobile para ter feedbacks mais rápidosParalelize seus testes web e mobile para ter feedbacks mais rápidos
Paralelize seus testes web e mobile para ter feedbacks mais rápidosElias Nogueira
 
Como 4 Agile Coaches trabalham em uma Transformação Ágil
Como 4 Agile Coaches trabalham em uma Transformação Ágil Como 4 Agile Coaches trabalham em uma Transformação Ágil
Como 4 Agile Coaches trabalham em uma Transformação Ágil Elias Nogueira
 
BDD não é automação de teste - Scrum Gathering
BDD não é automação de teste - Scrum GatheringBDD não é automação de teste - Scrum Gathering
BDD não é automação de teste - Scrum GatheringElias Nogueira
 
Como criar e executar testes paralelos web usando Selenium e containers
Como criar e executar testes paralelos web usando Selenium e containersComo criar e executar testes paralelos web usando Selenium e containers
Como criar e executar testes paralelos web usando Selenium e containersElias Nogueira
 
Improve Yourself -- Learn the Skills, Join the Community - Tests
Improve Yourself -- Learn the Skills, Join the Community - TestsImprove Yourself -- Learn the Skills, Join the Community - Tests
Improve Yourself -- Learn the Skills, Join the Community - TestsElias Nogueira
 
BDD não é Automação de Testes
BDD não é Automação de TestesBDD não é Automação de Testes
BDD não é Automação de TestesElias Nogueira
 
Criando uma grid para execução de testes paralelo com Appium
Criando uma grid para execução de testes paralelo com AppiumCriando uma grid para execução de testes paralelo com Appium
Criando uma grid para execução de testes paralelo com AppiumElias Nogueira
 
Como ter sucesso ministrando uma palestra técnica
Como ter sucesso ministrando uma palestra técnicaComo ter sucesso ministrando uma palestra técnica
Como ter sucesso ministrando uma palestra técnicaElias Nogueira
 
Quais são os steps de que deve conter na sua pipeline?
Quais são os steps de que deve conter na sua pipeline?Quais são os steps de que deve conter na sua pipeline?
Quais são os steps de que deve conter na sua pipeline?Elias Nogueira
 
Testes em todos os niveis de planejamento
Testes em todos os niveis de planejamentoTestes em todos os niveis de planejamento
Testes em todos os niveis de planejamentoElias Nogueira
 
Coaching the Agile Coach
Coaching the Agile CoachCoaching the Agile Coach
Coaching the Agile CoachElias Nogueira
 
Java Test Automation for REST, Web and Mobile
Java Test Automation for REST, Web and MobileJava Test Automation for REST, Web and Mobile
Java Test Automation for REST, Web and MobileElias Nogueira
 
Trust Your Pipeline - Automatically Testing and End-to-End Java Application
Trust Your Pipeline - Automatically Testing and End-to-End Java ApplicationTrust Your Pipeline - Automatically Testing and End-to-End Java Application
Trust Your Pipeline - Automatically Testing and End-to-End Java ApplicationElias Nogueira
 
O que é um Agile Coach
O que é um Agile CoachO que é um Agile Coach
O que é um Agile CoachElias Nogueira
 
Criando uma grid para execução de teste automatizado funcional e e2e
Criando uma grid para execução de teste automatizado funcional e e2eCriando uma grid para execução de teste automatizado funcional e e2e
Criando uma grid para execução de teste automatizado funcional e e2eElias Nogueira
 
A importancia de testes em todos os aspectos
A importancia de testes em todos os aspectosA importancia de testes em todos os aspectos
A importancia de testes em todos os aspectosElias Nogueira
 

Mais de Elias Nogueira (20)

Coach por Imersão - Buscando a excelência técnica com o time
Coach por Imersão - Buscando a excelência técnica com o timeCoach por Imersão - Buscando a excelência técnica com o time
Coach por Imersão - Buscando a excelência técnica com o time
 
O Agile Coach pode (e muitas vezes deve) ser técnico
O Agile Coach pode (e muitas vezes deve) ser técnicoO Agile Coach pode (e muitas vezes deve) ser técnico
O Agile Coach pode (e muitas vezes deve) ser técnico
 
Create an architecture for web test automation
Create an architecture for web test automationCreate an architecture for web test automation
Create an architecture for web test automation
 
Paralelize seus testes web e mobile para ter feedbacks mais rápidos
Paralelize seus testes web e mobile para ter feedbacks mais rápidosParalelize seus testes web e mobile para ter feedbacks mais rápidos
Paralelize seus testes web e mobile para ter feedbacks mais rápidos
 
Como 4 Agile Coaches trabalham em uma Transformação Ágil
Como 4 Agile Coaches trabalham em uma Transformação Ágil Como 4 Agile Coaches trabalham em uma Transformação Ágil
Como 4 Agile Coaches trabalham em uma Transformação Ágil
 
BDD não é automação de teste - Scrum Gathering
BDD não é automação de teste - Scrum GatheringBDD não é automação de teste - Scrum Gathering
BDD não é automação de teste - Scrum Gathering
 
Como criar e executar testes paralelos web usando Selenium e containers
Como criar e executar testes paralelos web usando Selenium e containersComo criar e executar testes paralelos web usando Selenium e containers
Como criar e executar testes paralelos web usando Selenium e containers
 
Improve Yourself -- Learn the Skills, Join the Community - Tests
Improve Yourself -- Learn the Skills, Join the Community - TestsImprove Yourself -- Learn the Skills, Join the Community - Tests
Improve Yourself -- Learn the Skills, Join the Community - Tests
 
BDD não é Automação de Testes
BDD não é Automação de TestesBDD não é Automação de Testes
BDD não é Automação de Testes
 
Criando uma grid para execução de testes paralelo com Appium
Criando uma grid para execução de testes paralelo com AppiumCriando uma grid para execução de testes paralelo com Appium
Criando uma grid para execução de testes paralelo com Appium
 
Como ter sucesso ministrando uma palestra técnica
Como ter sucesso ministrando uma palestra técnicaComo ter sucesso ministrando uma palestra técnica
Como ter sucesso ministrando uma palestra técnica
 
Quais são os steps de que deve conter na sua pipeline?
Quais são os steps de que deve conter na sua pipeline?Quais são os steps de que deve conter na sua pipeline?
Quais são os steps de que deve conter na sua pipeline?
 
Tem que testar mesmo?
Tem que testar mesmo?Tem que testar mesmo?
Tem que testar mesmo?
 
Testes em todos os niveis de planejamento
Testes em todos os niveis de planejamentoTestes em todos os niveis de planejamento
Testes em todos os niveis de planejamento
 
Coaching the Agile Coach
Coaching the Agile CoachCoaching the Agile Coach
Coaching the Agile Coach
 
Java Test Automation for REST, Web and Mobile
Java Test Automation for REST, Web and MobileJava Test Automation for REST, Web and Mobile
Java Test Automation for REST, Web and Mobile
 
Trust Your Pipeline - Automatically Testing and End-to-End Java Application
Trust Your Pipeline - Automatically Testing and End-to-End Java ApplicationTrust Your Pipeline - Automatically Testing and End-to-End Java Application
Trust Your Pipeline - Automatically Testing and End-to-End Java Application
 
O que é um Agile Coach
O que é um Agile CoachO que é um Agile Coach
O que é um Agile Coach
 
Criando uma grid para execução de teste automatizado funcional e e2e
Criando uma grid para execução de teste automatizado funcional e e2eCriando uma grid para execução de teste automatizado funcional e e2e
Criando uma grid para execução de teste automatizado funcional e e2e
 
A importancia de testes em todos os aspectos
A importancia de testes em todos os aspectosA importancia de testes em todos os aspectos
A importancia de testes em todos os aspectos
 

Automação e virtualização de serviços

  • 1. Automação e Virtualização de serviços REST com RestAssured + Wiremock + Docker @eliasnogueira
  • 2. Passos... 1 Entender a documentação da API 2 Pensar nos testes com uma divisão de pipeline 3 Criar uma versão inicial da arquitetura 4 Criar os testes e definir as suítes de testes 5 Criar mocks para resolver problemas * massa de dados, dependências, indisponibilidades
  • 3. API do TDC https://www.globalcode.com.br/api Expõe a API de consulta a: § Eventos § Modalidades § Coordenadores § Palestrantes § Palestras Através de um ClientID e um Secret é gerado um Access-Token em OAuth2 Possui a documentação via OpenAPI para download na própria página de acesso
  • 5. Entender os controllers § operações § endpoints § parâmetros de entrada § saída § autenticação
  • 6. 2. Pensar nos testes com uma divisão de pipeline
  • 7. API Pipeline Health Check Contrato Funcional Aceitação Garantir que o endpoint está respondendo HTTP 200 Garantir que o endpoint não teve seus atributos alterados Garantir que o endpoint funciona ou apresenta os resultados de falha esperados Garantir que um conjunto de endpoints funcionam como na UI
  • 9. Arquitetura src test Geração do Access Token necessário para a execução dos testes Leitor de Configurações para ler, ao menos, os dados de autenticação beans e builders suportar melhor a escrita dos testes BaseTest para remover a duplicidade de pré-condição json schemas schemas dos recursos para o teste de contrato Suítes de Teste habilitará a rápida execução de testes
  • 10. 4. Criar testes e definir as suítes de teste
  • 11. Rest-Assured http://rest-assured.io DSL Java para testar e validar APIs REST. import static io.restassured.RestAssured.*; import static org.hamcrest.Matchers.*; public class ExemploRestAssured { @Test public void boasVindas() { given(). param("nome", "Elias"). when(). post("/cadastro"). then(). body("mensagem", is("Olá Elias")); } }
  • 12. Rest-Assured http://rest-assured.io DSL Java para testar e validar APIs REST. import static io.restassured.RestAssured.*; import static org.hamcrest.Matchers.*; public class ExemploRestAssured { @Test public void boasVindas() { given(). param("nome", "Elias"). when(). post("/cadastro"). then(). body("mensagem", is("Olá Elias")); } } importação das bibliotecas necessárias
  • 13. Rest-Assured http://rest-assured.io DSL Java para testar e validar APIs REST. import static io.restassured.RestAssured.*; import static org.hamcrest.Matchers.*; public class ExemploRestAssured { @Test public void boasVindas() { given(). param("nome", "Elias"). when(). post("/cadastro"). then(). body("mensagem", is("Olá Elias")); } } pré-condição para a requisição
  • 14. Rest-Assured http://rest-assured.io DSL Java para testar e validar APIs REST. import static io.restassured.RestAssured.*; import static org.hamcrest.Matchers.*; public class ExemploRestAssured { @Test public void boasVindas() { given(). param("nome", "Elias"). when(). post("/cadastro"). then(). body("mensagem", is("Olá Elias")); } } ação (requisição)
  • 15. Rest-Assured http://rest-assured.io DSL Java para testar e validar APIs REST. import static io.restassured.RestAssured.*; import static org.hamcrest.Matchers.*; public class ExemploRestAssured { @Test public void boasVindas() { given(). param("nome", "Elias"). when(). post("/cadastro"). then(). body("mensagem", is("Olá Elias")); } } validação dos dados de retorno
  • 16. Gerar do Access-Token public String getAccessToken() { Configuration configuration = new Configuration(); String username = configuration.getAuthenticationUsername(); String password = configuration.getAuthenticationPassword(); baseURI = configuration.getAPIURL(); basePath = configuration.getAPIOauthContext(); return given(). auth() .preemptive().basic(username, password). when(). get("/"). then(). extract(). path("Access-Token"); }
  • 17. Gerar do Access-Token public String getAccessToken() { Configuration configuration = new Configuration(); String username = configuration.getAuthenticationUsername(); String password = configuration.getAuthenticationPassword(); baseURI = configuration.getAPIURL(); basePath = configuration.getAPIOauthContext(); return given(). auth() .preemptive().basic(username, password). when(). get("/"). then(). extract(). path("Access-Token"); } a autenticação é enviada como pré-condição
  • 18. Gerar do Access-Token public String getAccessToken() { Configuration configuration = new Configuration(); String username = configuration.getAuthenticationUsername(); String password = configuration.getAuthenticationPassword(); baseURI = configuration.getAPIURL(); basePath = configuration.getAPIOauthContext(); return given(). auth() .preemptive().basic(username, password). when(). get("/"). then(). extract(). path("Access-Token"); } access-token é retornado como String
  • 19. Leitor de Configurações public String getAccessToken() { Configuration configuration = new Configuration(); String username = configuration.getAuthenticationUsername(); String password = configuration.getAuthenticationPassword(); baseURI = configuration.getAPIURL(); basePath = configuration.getAPIOauthContext(); return given(). auth() .preemptive().basic(username, password). when(). get("/"). then(). extract(). path("Access-Token"); } lê dados de autenticação
  • 20. Leitor de Configurações public String getAccessToken() { Configuration configuration = new Configuration(); String username = configuration.getAuthenticationUsername(); String password = configuration.getAuthenticationPassword(); baseURI = configuration.getAPIURL(); basePath = configuration.getAPIOauthContext(); return given(). auth() .preemptive().basic(username, password). when(). get("/"). then(). extract(). path("Access-Token"); } lê dados para acesso ao token
  • 21. BaseTest public abstract class BaseTest { protected static String accessToken; @BeforeClass(alwaysRun = true) public static void beforeClass() { Configuration configuration = new Configuration(); accessToken = new GenerateAccessToken(). getAccessToken(); baseURI = configuration.getAPIURL(); basePath = configuration.getPublico(); } } Código executado antes de cada teste
  • 22. BaseTest public abstract class BaseTest { protected static String accessToken; @BeforeClass(alwaysRun = true) public static void beforeClass() { Configuration configuration = new Configuration(); accessToken = new GenerateAccessToken(). getAccessToken(); baseURI = configuration.getAPIURL(); basePath = configuration.getPublico(); } } Código executado antes de cada teste accessToken que será acessado pelas classes de teste
  • 23. BaseTest public abstract class BaseTest { protected static String accessToken; @BeforeClass(alwaysRun = true) public static void beforeClass() { Configuration configuration = new Configuration(); accessToken = new GenerateAccessToken(). getAccessToken(); baseURI = configuration.getAPIURL(); basePath = configuration.getPublico(); } } Código executado antes de cada teste gera o accessToken apenas uma vez para a execução de teste
  • 24. BaseTest public abstract class BaseTest { protected static String accessToken; @BeforeClass(alwaysRun = true) public static void beforeClass() { Configuration configuration = new Configuration(); accessToken = new GenerateAccessToken(). getAccessToken(); baseURI = configuration.getAPIURL(); basePath = configuration.getPublico(); } } Código executado antes de cada teste chamada da classe de geração do token
  • 25. BaseTest public abstract class BaseTest { protected static String accessToken; @BeforeClass(alwaysRun = true) public static void beforeClass() { Configuration configuration = new Configuration(); accessToken = new GenerateAccessToken(). getAccessToken(); baseURI = configuration.getAPIURL(); basePath = configuration.getPublico(); } } Código executado antes de cada teste necessário informar novamente o apontamento da API * porque já foi apontado na geração do access token
  • 26. health-check Garantir que o endpoint está respondendo
  • 27. heath-check Apenas validamos se o statuscode é 200 public class EventoDetalheTest extends BaseTest { @Test(groups = { "health" }) public void healthCheck() { given(). auth().oauth2(accessToken). when(). get("evento/{id}", id). then(). statusCode(HttpStatus.SC_OK); }
  • 28. heath-check Apenas validamos se o statuscode é 200 tag de grupo para filtrar a execução public class EventoDetalheTest extends BaseTest { @Test(groups = { "health" }) public void healthCheck() { given(). auth().oauth2(accessToken). when(). get("evento/{id}", id). then(). statusCode(HttpStatus.SC_OK); }
  • 29. heath-check Apenas validamos se o statuscode é 200 public class EventoDetalheTest extends BaseTest { @Test(groups = { "health" }) public void healthCheck() { given(). auth().oauth2(accessToken). when(). get("evento/{id}", id). then(). statusCode(HttpStatus.SC_OK); } inserir sempre o access-token como pré-condição da requisição
  • 30. heath-check Apenas validamos se o statuscode é 200 public class EventoDetalheTest extends BaseTest { @Test(groups = { "health" }) public void healthCheck() { given(). auth().oauth2(accessToken). when(). get("evento/{id}", id). then(). statusCode(HttpStatus.SC_OK); } validar se o status code, e somente ele, é 200
  • 31. contrato Garantir que o endpoint não teve seus atributos alterados
  • 32. ● É o nome dado ao pacto entre o produtor e consumidor ● Garante que mudanças na API não invalidem o consumo: ● path ● parâmetros ● dados de envio (request) ● dados de retorno (response body) ● json-schema é um contrato que define os dados esperados, tipos e formatos de cada campo na resposta contrato
  • 33. { "nome": "Elias", "idade": 36 } { "$schema": "http://json-schema.org/draft-04/schema#", "type": "object", "properties": { "nome": { "type": "string" }, "idade": { "type": "integer" } }, "required": [ "nome", "idade" ], "additionalProperties": false } json-schema
  • 34. { "nome": "Elias", "idade": 36 } { "$schema": "http://json-schema.org/draft-04/schema#", "type": "object", "properties": { "nome": { "type": "string" }, "idade": { "type": "integer" } }, "required": [ "nome", "idade" ], "additionalProperties": false } json-schema possui o nome do atributo e o tipo de dados json-schema
  • 35. { "nome": "Elias", "idade": 36 } { "$schema": "http://json-schema.org/draft-04/schema#", "type": "object", "properties": { "nome": { "type": "string" }, "idade": { "type": "integer" } }, "required": [ "nome", "idade" ], "additionalProperties": false } os dois atributos devem estar presentes, obrigatoriamente json-schema
  • 36. { "nome": "Elias", "idade": 36 } { "$schema": "http://json-schema.org/draft-04/schema#", "type": "object", "properties": { "nome": { "type": "string" }, "idade": { "type": "integer" } }, "required": [ "nome", "idade" ], "additionalProperties": false } json-schema nenhum outro atributo é permitido
  • 37. teste funcional na minha máquina funciona ¯_(ツ)_/¯
  • 38. funcional Validar cenários positivos e negativos (caminho feliz | fluxo exceção) @Test(groups = {"funcional"}) public void validarEventoPeloID() { given(). auth().oauth2(accessToken). when(). get("evento/{id}", 110). then(). statusCode(HttpStatus.SC_OK). body("[0].id", is(110)). body("[0].descricao", is("TDC 2019 Florianópolis")). body("[0].chave", is("tdc-2019-florianopolis")). body("[0].ativo", is(true)). body("[0].dias", is(5)). body("[0].dataInicio", is("2019-04-23 00:00:00")). body("[0].dataTermino", is("2019-04-27 00:00:00")); }
  • 39. funcional Validar cenários positivos e negativos (caminho feliz | fluxo exceção) @Test(groups = {"funcional"}) public void validarEventoPeloID() { given(). auth().oauth2(accessToken). when(). get("evento/{id}", 110). then(). statusCode(HttpStatus.SC_OK). body("[0].id", is(110)). body("[0].descricao", is("TDC 2019 Florianópolis")). body("[0].chave", is("tdc-2019-florianopolis")). body("[0].ativo", is(true)). body("[0].dias", is(5)). body("[0].dataInicio", is("2019-04-23 00:00:00")). body("[0].dataTermino", is("2019-04-27 00:00:00")); } tag de grupo para filtrar a execução
  • 40. funcional Validar cenários positivos e negativos (caminho feliz | fluxo exceção) @Test(groups = {"funcional"}) public void validarEventoPeloID() { given(). auth().oauth2(accessToken). when(). get("evento/{id}", 110). then(). statusCode(HttpStatus.SC_OK). body("[0].id", is(110)). body("[0].descricao", is("TDC 2019 Florianópolis")). body("[0].chave", is("tdc-2019-florianopolis")). body("[0].ativo", is(true)). body("[0].dias", is(5)). body("[0].dataInicio", is("2019-04-23 00:00:00")). body("[0].dataTermino", is("2019-04-27 00:00:00")); } requisição para obter o detalhe de um determinado evento
  • 41. funcional Validar cenários positivos e negativos (caminho feliz | fluxo exceção) @Test(groups = {"funcional"}) public void validarEventoPeloID() { given(). auth().oauth2(accessToken). when(). get("evento/{id}", 110). then(). statusCode(HttpStatus.SC_OK). body("[0].id", is(110)). body("[0].descricao", is("TDC 2019 Florianópolis")). body("[0].chave", is("tdc-2019-florianopolis")). body("[0].ativo", is(true)). body("[0].dias", is(5)). body("[0].dataInicio", is("2019-04-23 00:00:00")). body("[0].dataTermino", is("2019-04-27 00:00:00")); } validação dos dados de retorno (body) * [0] existe ali porque o retorno é um array de uma posição * é um possível bug da implementação
  • 42. aceitação Garantir que um conjunto de endpoints funcionam como na UI
  • 43. Testar com a perspectiva do usuário ● Entrar no evento The Developers Conference Florianópolis ● Clicar na Trilha DevTest ● Visualizar os detalhes da palestra Automação e Virtualização de serviços REST com RestAssured + Wiremock + Docker
  • 44. aceitação @Test(groups = {"aceitacao"}) public void visualizaDetalhes_EncontrandoDados() throws ObjetoNotFoundException { String tituloPalestra = "Automação e Virtualização de serviços REST "; Evento evento = encontraEvento("TDC 2019 Florianópolis"); Modalidade trilha = encontraTrilha(evento, "Trilha DevTest"); Palestra palestra = encontraPalestra(evento, trilha, tituloPalestra); given(). auth(). oauth2(accessToken). pathParam("eventoID", evento.getId()). pathParam("modalidadeID", trilha.getId()). pathParam("palestraID", palestra.getId()). when(). get("/evento/{eventoID}/modalidade/{modalidadeID}/palestra/{palestraID}/palestrantes"). then(). statusCode(200). body("[0].member.nome", is("Elias Nogueira")). body("[0].member.empresa", is("Sicredi")); }
  • 45. aceitação @Test(groups = {"aceitacao"}) public void visualizaDetalhes_EncontrandoDados() throws ObjetoNotFoundException { String tituloPalestra = "Automação e Virtualização de serviços REST "; Evento evento = encontraEvento("TDC 2019 Florianópolis"); Modalidade trilha = encontraTrilha(evento, "Trilha DevTest"); Palestra palestra = encontraPalestra(evento, trilha, tituloPalestra); given(). auth(). oauth2(accessToken). pathParam("eventoID", evento.getId()). pathParam("modalidadeID", trilha.getId()). pathParam("palestraID", palestra.getId()). when(). get("/evento/{eventoID}/modalidade/{modalidadeID}/palestra/{palestraID}/palestrantes"). then(). statusCode(200). body("[0].member.nome", is("Elias Nogueira")). body("[0].member.empresa", is("Sicredi")); } funções auxiliares para chamadas a cada ação do usuário
  • 46. aceitação @Test(groups = {"aceitacao"}) public void visualizaDetalhes_EncontrandoDados() throws ObjetoNotFoundException { String tituloPalestra = "Automação e Virtualização de serviços REST "; Evento evento = encontraEvento("TDC 2019 Florianópolis"); Modalidade trilha = encontraTrilha(evento, "Trilha DevTest"); Palestra palestra = encontraPalestra(evento, trilha, tituloPalestra); given(). auth(). oauth2(accessToken). pathParam("eventoID", evento.getId()). pathParam("modalidadeID", trilha.getId()). pathParam("palestraID", palestra.getId()). when(). get("/evento/{eventoID}/modalidade/{modalidadeID}/palestra/{palestraID}/palestrantes"). then(). statusCode(200). body("[0].member.nome", is("Elias Nogueira")). body("[0].member.empresa", is("Sicredi")); } uso dos dados obtidos para a requisição
  • 48. ● Forma de simular comportamentos de componentes baseados em API ● Habilita o uso de serviços virtuais ao invés de serviços de produção mesmo que componentes chave não estejam disponíveis service virtualization
  • 49. service virtualization { "id" : "f238845e-369c-4a34-aa69-04d9240d7fb5", "name" : "evento_modalidade_palestra", "request" : { "urlPattern" : "/v1/publico/evento/110/modalidade/2685/palestra/10083", "method" : "GET" }, "response" : { "status" : 200, "bodyFileName" : "evento_modalidade_palestra_data.json", "headers" : { "Authorization": "*" } }, "persistent" : true, "insertionIndex" : 1 }
  • 50. service virtualization { "id" : "f238845e-369c-4a34-aa69-04d9240d7fb5", "name" : "evento_modalidade_palestra", "request" : { "urlPattern" : "/v1/publico/evento/110/modalidade/2685/palestra/10083", "method" : "GET" }, "response" : { "status" : 200, "bodyFileName" : "evento_modalidade_palestra_data.json", "headers" : { "Authorization": "*" } }, "persistent" : true, "insertionIndex" : 1 } sempre que uma requisição for igual a esta URL (inclusive com os dados)
  • 51. service virtualization { "id" : "f238845e-369c-4a34-aa69-04d9240d7fb5", "name" : "evento_modalidade_palestra", "request" : { "urlPattern" : "/v1/publico/evento/110/modalidade/2685/palestra/10083", "method" : "GET" }, "response" : { "status" : 200, "bodyFileName" : "evento_modalidade_palestra_data.json", }, "persistent" : true, "insertionIndex" : 1 } a api responderá os dados abaixo...
  • 52. service virtualization { "id": 10083, "slot": 6, "ordem": 1, "titulo": "Automação e Virtualização de serviços REST...", "descricao": ”Você sempre quis aprender a como testar...", "tipo": 2, "horario": "16:40" } dados de retorno