From 534a0ab82ee57cff3ce590b8989c1472a6d833fe Mon Sep 17 00:00:00 2001 From: SanriaArgos Date: Tue, 19 May 2026 00:56:30 +0300 Subject: [PATCH] rest-countries-tests: solution --- pom.xml | 7 ++ .../java/restcountries/RestCountriesTest.java | 100 ++++++++++++++++++ tasks/classwork/api-tests/api-notes.md | 37 +++++++ .../classwork/rest-countries-tests/REPORT.md | 43 ++++++++ 4 files changed, 187 insertions(+) create mode 100644 src/test/java/hse/java/restcountries/RestCountriesTest.java create mode 100644 tasks/classwork/api-tests/api-notes.md create mode 100644 tasks/classwork/rest-countries-tests/REPORT.md diff --git a/pom.xml b/pom.xml index de78097..bf6448a 100644 --- a/pom.xml +++ b/pom.xml @@ -79,6 +79,13 @@ jackson-databind 2.17.2 + + + io.rest-assured + rest-assured + 5.5.0 + test + com.google.code.gson diff --git a/src/test/java/hse/java/restcountries/RestCountriesTest.java b/src/test/java/hse/java/restcountries/RestCountriesTest.java new file mode 100644 index 0000000..fdd64c9 --- /dev/null +++ b/src/test/java/hse/java/restcountries/RestCountriesTest.java @@ -0,0 +1,100 @@ +package hse.java.restcountries; + +import org.junit.jupiter.api.*; +import io.restassured.RestAssured; +import static org.hamcrest.Matchers.*; +import org.junit.jupiter.params.provider.*; +import static io.restassured.RestAssured.*; +import org.junit.jupiter.params.ParameterizedTest; + +public class RestCountriesTest { + private static final String ALL_FIELDS = "name,capital,population,cca2,region,languages,currencies,independent"; + + @BeforeAll + static void setUp() { + RestAssured.baseURI = "https://restcountries.com/v3.1"; + } + + @Test + @Tag("rest-countries-tests-1") + void allList() { + given().queryParam("fields", ALL_FIELDS) + .when().get("/all") + .then().statusCode(200) + .body("size()", greaterThan(0)); + } + + @Test + @Tag("rest-countries-tests-2") + void europeRegion() { + given().queryParam("fields", "name,region") + .when().get("/region/europe") + .then().statusCode(200) + .body("region", everyItem(equalTo("Europe"))) + .body("name.common", hasItems("Austria", "Serbia", "Hungary")); + } + + @Test + @Tag("rest-countries-tests-1") + void badCountry() { + when().get("/name/nonexistentcountryxyz") + .then().statusCode(404) + .body("status", equalTo(404)) + .body("message", not(emptyString())); + } + + @ParameterizedTest + @Tag("rest-countries-tests-2") + @CsvSource({ + "russia, Moscow", + "austria, Vienna", + "serbia, Belgrade", + "hungary, Budapest" + }) + void nameCapital(String name, String capital) { + given().queryParam("fields", "name,capital") + .when().get("/name/" + name) + .then().statusCode(200) + .body("capital.flatten()", hasItem(capital)); + } + + @Test + @Tag("rest-countries-tests-2") + void fieldsOnly() { + given().queryParam("fields", "name,cca2") + .when().get("/alpha/at") + .then().statusCode(200) + .body("name.common", equalTo("Austria")) + .body("cca2", equalTo("AT")) + .body("capital", nullValue()); + } + + @Test + @Tag("rest-countries-tests-1") + void populationField() { + given().queryParam("fields", "name,population") + .when().get("/all") + .then().statusCode(200) + .body("population", everyItem(notNullValue())); + } + + @Test + @Tag("rest-countries-tests-2") + void euroCurrency() { + given().queryParam("fields", "name,currencies") + .when().get("/currency/eur") + .then().statusCode(200) + .body("name.common", hasItem("Austria")); + } + + @Test + @Tag("rest-countries-tests-2") + void alphaKp() { + given().queryParam("fields", "name,capital,cca2") + .when().get("/alpha/kp") + .then().statusCode(200) + .body("name.common", equalTo("North Korea")) + .body("cca2", equalTo("KP")) + .body("capital", hasItem("Pyongyang")); + } +} \ No newline at end of file diff --git a/tasks/classwork/api-tests/api-notes.md b/tasks/classwork/api-tests/api-notes.md new file mode 100644 index 0000000..25fa075 --- /dev/null +++ b/tasks/classwork/api-tests/api-notes.md @@ -0,0 +1,37 @@ +# API notes + +**Базовый адрес API**: `https://restcountries.com/v3.1` + +## Доступные эндпоинты + +| **Endpoint** | **Что проверяем** | +|----------------------------|-------------------------------| +| `GET /all?fields=...` | список стран с нужными полями | +| `GET /name/{name}` | поиск страны по названию | +| `GET /alpha/{code}` | поиск страны по ISO-коду | +| `GET /currency/{currency}` | поиск стран по валюте | +| `GET /region/{region}` | поиск стран по региону | + +## Структура успешного ответа + +* Для `/all`, `/name`, `/currency` и `/region` возвращаем массив стран. +* Для `/alpha/{code}` - один объект страны. +* Используемые поля: + +| **Поле** | **Что означает** | **Пример** | +|---------------|--------------------------------|--------------| +| `name.common` | обычное название страны | `Austria` | +| `capital` | список столиц | `["Vienna"]` | +| `population` | население | `8935112` | +| `cca2` | код страны из первых двух букв | `AT` | +| `region` | регион | `Europe` | + +## Коды ошибок и их формат + +Если страны нет, то возвращаем `404`. Также в ответе есть поля `status` и `message`, поэтому в тесте можем проверять как HTTP-код, так и сам JSON. + +## Лимиты, кеширование, специфика поведения + +* Все тесты независимы. Они ничего не сохраняют, не меняют общий state. Просто выполняют GET-запросы к публичному API. +* Для `/all` используется параметр `fields`, т.к так получаем только нужные поля и не зависим от полного ответа API. +* В тестах участвует Россия, Австрия, Сербия, Венгрия и Северная Корея :) Для последней используется запрос `/alpha/kp`, поскольку название состоит из двух слов, а пробел может по-разному кодироваться. diff --git a/tasks/classwork/rest-countries-tests/REPORT.md b/tasks/classwork/rest-countries-tests/REPORT.md new file mode 100644 index 0000000..b2fd67a --- /dev/null +++ b/tasks/classwork/rest-countries-tests/REPORT.md @@ -0,0 +1,43 @@ +# REPORT + +## 1. Какой API выбрала и почему + +Я выбрала REST Countries API, т.к. это было быстрее всего. Кроме того, у него есть разные эндпоинты, JSON-ответы, поиск по параметрам и нормальные ошибки клиента. + +## 2. Покрытые сценарии +| Категория | Сценарий | Статус | +|------------------------|-----------------------------------------------------------|-------------| +| Happy path | `/all?fields=...` возвращает непустой список стран | сделано | +| Happy path | Северная Корея находится по alpha-коду `KP` | сделано | +| Параметры запроса | `fields=name,cca2` возвращает только нужные поля | сделано | +| Ошибки клиента | несуществующая страна возвращает `404` | сделано | +| Контракт ответа | у стран из `/all` есть поле `population` | сделано | +| Параметризованный тест | Россия. Австрия, Венгрия и Сербия возвращают свои столицы | сделано | +| Поиск по валюте | среди стран с валютой EUR есть Австрия | сделано | +| Поиск по региону | регион Europe включает в себя Австрию, Венгрию и Сербию | сделано | + +## 3. Что узнала об API + +* Эндпоинты `/all` лучше вызывать с параметром `fields`, т.к при обычном `/all` API может вернуть ошибку `400` из-за слишком большого ответа. +* `/name/{name}` возвращает массив, а `/alpha/{code}` возвращает один объект. + +## 4. Инструменты + +* Для тестов использовала REST Assured, т.к он удобен для проверки публичного REST API. Понравилось, что код получается коротким. +* Также из лекции использовала: + * RestAssured.baseURI + * given().queryParam(...).when().get(...).then() + * statusCode(...) + * body(...) + * @Test + * @BeforeAll + * @ParameterizedTest + * @CsvSource + * @Tag + +## 5. Запуск + +Чтобы запустить все тесты: +``` +mvn test +``` \ No newline at end of file