Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,13 @@
<artifactId>jackson-databind</artifactId>
<version>2.17.2</version>
</dependency>
<!-- REST Assured для интеграционных HTTP-тестов -->
<dependency>
<groupId>io.rest-assured</groupId>
<artifactId>rest-assured</artifactId>
<version>5.5.0</version>
<scope>test</scope>
</dependency>
<!-- Source: https://mvnrepository.com/artifact/com.google.code.gson/gson -->
<dependency>
<groupId>com.google.code.gson</groupId>
Expand Down
100 changes: 100 additions & 0 deletions src/test/java/hse/java/restcountries/RestCountriesTest.java
Original file line number Diff line number Diff line change
@@ -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"));
}
}
37 changes: 37 additions & 0 deletions tasks/classwork/api-tests/api-notes.md
Original file line number Diff line number Diff line change
@@ -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`, поскольку название состоит из двух слов, а пробел может по-разному кодироваться.
43 changes: 43 additions & 0 deletions tasks/classwork/rest-countries-tests/REPORT.md
Original file line number Diff line number Diff line change
@@ -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
```