Как ты проводишь валидацию ответа API?

«Как ты проводишь валидацию ответа API?» — вопрос из категории API тестирование, который задают на 24% собеседований AQA / Automation. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

При валидации API-ответов я использую многоуровневый подход, который охватывает все аспекты — от HTTP-статусов до бизнес-логики.

Мой стандартный стек для API-тестирования:

  • REST Assured (Java) или Supertest (Node.js) для HTTP-запросов
  • JSON Schema Validator для проверки структуры
  • Hamcrest или AssertJ для читаемых assertions
  • Allure для отчетности

Пример комплексной валидации на Java (REST Assured):

@Test
public void getUser_ShouldReturnValidResponse() {
    given()
        .baseUri("https://api.example.com")
        .header("Authorization", "Bearer " + token)
    .when()
        .get("/users/{id}", 123)
    .then()
        // 1. Валидация HTTP-уровня
        .statusCode(200)
        .contentType(ContentType.JSON)
        .header("Cache-Control", "max-age=3600")

        // 2. Валидация JSON-схемы
        .body(matchesJsonSchemaInClasspath("schemas/user-schema.json"))

        // 3. Валидация конкретных полей
        .body("id", equalTo(123))
        .body("name", not(emptyString()))
        .body("email", matchesPattern("^[\w-.]+@([\w-]+\.)+[\w-]{2,4}$"))
        .body("roles", hasItems("USER", "EDITOR"))
        .body("address.city", equalTo("Moscow"))

        // 4. Валидация бизнес-правил
        .body("createdAt", lessThan("updatedAt"))
        .body("isActive", equalTo(true));
}

Для сложных сценариев я добавляю:

Валидацию контрактов (OpenAPI):

// Использую swagger-request-validator
SwaggerValidationFilter validationFilter = new SwaggerValidationFilter("openapi.yaml");

given()
    .filter(validationFilter)
    // ... остальные параметры
.then()
    .assertThat()
    .validationPassed(); // Проверка соответствия спецификации

Тестирование граничных случаев:

// Несуществующий пользователь
.when().get("/users/999999")
.then().statusCode(404)
       .body("error", equalTo("User not found"));

// Неавторизованный доступ
.when().get("/users/123")
.then().statusCode(401);

// Неверные параметры
.when().get("/users/abc")
.then().statusCode(400);

Валидацию производительности:

.when().get("/users/{id}", 123)
.then().time(lessThan(2000L)); // Ответ менее 2 секунд

Ключевые принципы моей валидации:

  1. Полнота: Проверяю статус, заголовки, структуру, типы данных, значения
  2. Изоляция: Каждый тест независим, использую тестовые данные
  3. Читаемость: Assertions должны явно показывать, что проверяется
  4. Поддержка: Все схемы и контракты хранятся в репозитории
  5. Интеграция: Тесты запускаются в CI/CD при каждом изменении API