From 8c90300ae2b8bd3b2e3f825a33bb329ab1c7263e Mon Sep 17 00:00:00 2001 From: ThomasTDS Date: Sat, 19 Sep 2026 16:56:23 -0300 Subject: [PATCH] =?UTF-8?q?Adiciona=20cen=C3=A1rio=20documentando=20bug=20?= =?UTF-8?q?de=20cria=C3=A7=C3=A3o=20sem=20campo=20obrigat=C3=B3rio=20(TC-0?= =?UTF-8?q?15)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fecha o loop da issue #8: POST /booking sem um campo obrigatório (ex: firstname) derruba a API com 500 em vez de rejeitar com 400. O cenário trava esse comportamento atual como um teste de regressão do bug conhecido — se um dia a API passar a devolver 400, o teste quebra de propósito, sinalizando que o bug foi corrigido e a issue pode ser fechada. Adiciona create_booking_raw ao BookingApiClient pra permitir mandar um payload propositalmente inválido, sem passar pela validação do Pydantic do create_booking normal. --- api/booking_api_client.py | 5 +++++ docs/test-cases.md | 1 + features/create_booking.feature | 11 +++++++++++ pyproject.toml | 1 + steps/test_booking_steps.py | 17 +++++++++++++++++ 5 files changed, 35 insertions(+) diff --git a/api/booking_api_client.py b/api/booking_api_client.py index 921572a..6ece8d5 100644 --- a/api/booking_api_client.py +++ b/api/booking_api_client.py @@ -32,6 +32,11 @@ def get_booking(self, booking_id: int) -> requests.Response: def create_booking(self, booking: Booking) -> requests.Response: return self.session.post(f"{self.base_url}/booking", json=booking.model_dump(exclude_none=True)) + # Recebe um dict cru (sem passar pela validação do Pydantic) para testes + # negativos que precisam mandar um payload propositalmente inválido. + def create_booking_raw(self, payload: dict[str, Any]) -> requests.Response: + return self.session.post(f"{self.base_url}/booking", json=payload) + def update_booking(self, booking_id: int, booking: Booking, token: str) -> requests.Response: return self.session.put( f"{self.base_url}/booking/{booking_id}", diff --git a/docs/test-cases.md b/docs/test-cases.md index cffe28f..eb9d67c 100644 --- a/docs/test-cases.md +++ b/docs/test-cases.md @@ -26,6 +26,7 @@ Legenda: | TC-012 | Atualização | Tentar atualizar parcialmente booking sem token (PATCH) | Negativo | Alta | Automatizado | [update_booking.feature:36](../features/update_booking.feature#L36) | | TC-013 | Atualização | Tentar atualizar booking com token inválido (PUT) | Negativo | Alta | Automatizado | [update_booking.feature:17](../features/update_booking.feature#L17) | | TC-014 | Remoção | Tentar remover um booking que não existe | Negativo | Baixa | Automatizado | [delete_booking.feature:16](../features/delete_booking.feature#L16) | +| TC-015 | Criação | Tentar criar booking sem um campo obrigatório (bug) | Negativo | Média | Automatizado | [create_booking.feature:13](../features/create_booking.feature#L13) | `BookingApiClient.get_booking_ids` também aceita filtro por `checkin`/`checkout`, mas o TC-006 cobre só `firstname`/`lastname`: o filtro por data na API pública de demonstração é conhecido por ser instável, e testá-lo arriscaria um teste flaky em vez de validar um comportamento real. diff --git a/features/create_booking.feature b/features/create_booking.feature index 592b0ea..ef89562 100644 --- a/features/create_booking.feature +++ b/features/create_booking.feature @@ -10,3 +10,14 @@ Feature: Criação de booking When ele cria um booking com dados válidos Then o booking deve ser criado com sucesso And o id do booking criado deve ser retornado + + # Bug real da API, documentado em + # https://github.com/ThomasTDS/qa-api-python/issues/8: em vez de rejeitar + # com 400, a API derruba com 500 quando falta um campo obrigatório. Esse + # cenário trava o comportamento atual; se um dia passar a devolver 400, + # é sinal de que o bug foi corrigido do lado de lá, e cabe atualizar o + # teste (e fechar a issue). + @TC-015 + Scenario: Tentar criar booking sem um campo obrigatório + When ele tenta criar um booking sem informar o firstname + Then a resposta deve indicar um erro interno do servidor diff --git a/pyproject.toml b/pyproject.toml index 384ec41..6edc503 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -49,6 +49,7 @@ markers = [ "TC-012: id do test case, ver docs/test-cases.md", "TC-013: id do test case, ver docs/test-cases.md", "TC-014: id do test case, ver docs/test-cases.md", + "TC-015: id do test case, ver docs/test-cases.md", ] [tool.ruff] diff --git a/steps/test_booking_steps.py b/steps/test_booking_steps.py index 8db0436..921e1c3 100644 --- a/steps/test_booking_steps.py +++ b/steps/test_booking_steps.py @@ -82,6 +82,23 @@ def id_do_booking_criado_deve_ser_retornado(context: Context) -> None: context.booking_id = body.bookingid +@when("ele tenta criar um booking sem informar o firstname") +def tenta_criar_booking_sem_firstname(context: Context) -> None: + payload = { + "lastname": "Ciclano", + "totalprice": 150, + "depositpaid": True, + "bookingdates": {"checkin": "2026-01-01", "checkout": "2026-01-05"}, + } + context.last_response = context.booking_client.create_booking_raw(payload) + + +@then("a resposta deve indicar um erro interno do servidor") +def resposta_indica_erro_interno_do_servidor(context: Context) -> None: + assert context.last_response is not None + assert context.last_response.status_code == 500 + + # CONSULTA @when("ele busca o booking pelo id") def busca_o_booking_pelo_id(context: Context) -> None: