Testes de integração para sua API

· 903 words · 5 minute read

Sumário 🔗

  1. Introdução
  2. Testando sua API

Se você chegou até esse post e não leu ainda sobre testes unitários, eu te convido a ler a parte 1.

Introdução 🔗

O teste de integração garante que módulos ou componentes combinados em grupos sejam testados. Esse processo visa verificar a eficiência e a segurança da comunicação entre sistemas. Ele se torna essencial para garantir que o software funcione sem erros de integração. Em resumo, o teste de integração testa desde a chamada a sua API ou CLI, até a persistência de dados no banco de dados ou integrações com terceiros.

Testando sua API 🔗

Arquitetura da API de Video Games

Vamos considerar uma API que gerencia jogos de video games onde ela precisa hora conectar no banco de dados, hora conectar em uma API de terceiros para buscar informações adicionais. Para testar essa API, podemos usar o Docker Compose para criar um ambiente de teste que inclua o banco de dados e a API de terceiros. No nosso exemplo, o banco de dados será o PostgreSQL e para a API de terceiros, vamos usar o Mock Server.

Abaixo está um exemplo completo de cada arquivo que precisamos para configurar o ambiente de teste com Docker Compose e os arquivos de Dockerfile para a nossa API e testes.

  1// docker-compose.yaml
  2
  3services:
  4  video-game-api:
  5    container_name: video-game-api
  6    ports:
  7      - 17020:17020
  8      - 17022:17022
  9    environment:
 10      DOCKER: "true"
 11      DATABASE_HOST: postgres-db
 12      DATABASE_PORT: 5432
 13      DATABASE_USER: postgres
 14      DATABASE_PASSWORD: postgres
 15      DATABASE_NAME: postgres
 16      DATABASE_SSL_MODE: disable
 17      REDIS_HOST: redis
 18      SERVICE_NAME: video-game-api
 19      VENDOR_IGDB_HOST: http://mock_igdb_service:1081
 20      VENDOR_TWITCH_HOST: http://mock_twitch_service:1080
 21      VENDOR_TWITCH_CLIENT_ID: client-id
 22      VENDOR_TWITCH_CLIENT_SECRET: client-secret
 23    build:
 24      context: .
 25      dockerfile: Dockerfile
 26    depends_on:
 27      postgres-db:
 28        condition: service_healthy
 29      mock_twitch_service:
 30        condition: service_started
 31      mock_igdb_service:
 32        condition: service_started
 33    networks:
 34      - video-game-api-network
 35
 36  integration-test:
 37    container_name: integration-test
 38    build:
 39      context: .
 40      dockerfile: Dockerfile.test
 41    environment:
 42      VIDEO_GAME_API_URL: http://video-game-api:17020
 43      VIDEO_GAME_GRPC_HOST: video-game-api:17022
 44    depends_on:
 45      video-game-api:
 46        condition: service_started
 47    networks:
 48      - video-game-api-network
 49
 50  postgres-db:
 51    container_name: postgres-db
 52    image: postgres:16.2-bullseye
 53    ports:
 54      - 5438:5432
 55    environment:
 56      POSTGRES_PASSWORD: postgres
 57      POSTGRES_USER: postgres
 58      POSTGRES_DB: postgres
 59    healthcheck:
 60      test: ["CMD-SHELL", "pg_isready -U postgres"]
 61      interval: 2s
 62      timeout: 10s
 63      retries: 20
 64    networks:
 65      - video-game-api-network
 66
 67  redis:
 68    container_name: redis
 69    image: redis:7-alpine
 70    ports:
 71      - "6379:6379"
 72
 73  mock_twitch_service:
 74    container_name: mock_twitch_service
 75    image: mockserver/mockserver
 76    ports:
 77      - "1080:1080"
 78    environment:
 79      SERVER_PORT: 1080
 80      MOCKSERVER_INITIALIZATION_JSON_PATH: /config/twitch_expectations.json
 81    volumes:
 82      - $PWD/config/mock/:/config/
 83    networks:
 84      - video-game-api-network
 85
 86  mock_igdb_service:
 87    container_name: mock_igdb_service
 88    image: mockserver/mockserver
 89    ports:
 90      - "1081:1081"
 91    environment:
 92      SERVER_PORT: 1081
 93      MOCKSERVER_INITIALIZATION_JSON_PATH: /config/igdb_expectations.json
 94    volumes:
 95      - $PWD/config/mock/:/config/
 96    networks:
 97      - video-game-api-network
 98
 99networks:
100  video-game-api-network:
101    driver: bridge
 1# Dockerfile
 2
 3FROM golang:1.24-bullseye AS build
 4
 5WORKDIR /src
 6
 7# Copy everything but defined in docker ignore file
 8COPY . .
 9
10# Build
11RUN go mod vendor
12RUN make build-linux-amd64
13
14#####################
15# Build final image #
16#####################
17FROM alpine AS bin
18
19# Copy from build
20COPY --from=build /src/build/video-game-api-linux-amd64 ./video-game-api
21COPY --from=build /src/db ./db
22
23# Specify the container's entrypoint as the action
24ENTRYPOINT ["./video-game-api"]
25
 1# Dockerfile.test
 2
 3FROM golang:1.24-bullseye
 4
 5WORKDIR /src
 6
 7# Copy everything but defined in docker ignore file
 8COPY . .
 9
10# Download dependencies
11RUN go mod vendor
12
13CMD [ "go", "test", "-v", "-race", "-timeout=30s", "-tags=integration", "./test/integration_test/..." ]
14

Agora que temos o ambiente configurado, podemos escrever os testes de integração. Vamos criar um arquivo de teste chamado console_http_test.go dentro do diretório test/integration_test.

 1func TestConsoleSearch_Http(t *testing.T) {
 2  apiURL := os.Getenv("VIDEO_GAME_API_URL")
 3  url := apiURL + "/consoles/b171ae30-2d02-4da2-98b4-33ad2c331669"
 4
 5  req, err := http.NewRequest(http.MethodGet, url, nil)
 6  require.NoError(t, err)
 7
 8  req.Header.Set("Accept", "application/json")
 9  req.Header.Set("Content-Type", "application/json")
10
11  client := &http.Client{}
12
13  resp, err := client.Do(req)
14  require.NoError(t, err)
15
16  defer resp.Body.Close()
17
18  require.Equal(t, http.StatusOK, resp.StatusCode)
19
20  resbody, err := io.ReadAll(resp.Body)
21  require.NoError(t, err)
22
23  var console model.Console
24
25  err = json.Unmarshal(resbody, &console)
26  require.NoError(t, err)
27
28  assert.Equal(t, "b171ae30-2d02-4da2-98b4-33ad2c331669", console.ID)
29  assert.Equal(t, "Xbox 360", console.Name)
30  assert.Equal(t, "Microsoft", console.Manufacturer)
31  assert.Equal(t, "2005-11-22", console.ReleaseDate)
32}
33
  1. Obtenha a URL da API a partir da variável de ambiente VIDEO_GAME_API_URL. Nesse caso ela é definida no docker-compose.yaml e aponta para o serviço video-game-api.
1apiURL := os.Getenv("VIDEO_GAME_API_URL")
  1. Crie uma nova requisição HTTP para a rota /consoles/{id}.
1url := apiURL + "/consoles/b171ae30-2d02-4da2-98b4-33ad2c331669"
2req, err := http.NewRequest(http.MethodGet, url, nil)
  1. Defina os cabeçalhos Accept e Content-Type para application/json.
1req.Header.Set("Accept", "application/json")
2req.Header.Set("Content-Type", "application/json")
  1. Use o cliente HTTP para enviar a requisição e obter a resposta.
1client := &http.Client{}
2resp, err := client.Do(req)
  1. Verifique se o status da resposta é 200 OK.
1require.Equal(t, http.StatusOK, resp.StatusCode)
  1. Leia o corpo da resposta e verifique se não houve erro.
1resbody, err := io.ReadAll(resp.Body)
2require.NoError(t, err)
3
4var console model.Console
5
6err = json.Unmarshal(resbody, &console)
7require.NoError(t, err)
  1. Verifique se os dados retornados estão corretos.
1assert.Equal(t, "b171ae30-2d02-4da2-98b4-33ad2c331669", console.ID)
2assert.Equal(t, "Xbox 360", console.Name)
3assert.Equal(t, "Microsoft", console.Manufacturer)
4assert.Equal(t, "2005-11-22", console.ReleaseDate)

Para executar os testes de integração, você pode usar o seguinte comando:

1docker compose run --build --rm integration-test

Dessa forma conseguimos garantir que a nossa API está funcionando corretamente iniciando pela chamada HTTP e validando a resposta.

Deixo aqui uma sugestão de repositório com testes de integração: Video Game API.

Na segunda parte deste post, vamos ver como podemos testar CLIs.