Q37 of 40 · REST Assured
How would you handle backwards-compatible API changes that require gradual test updates?
Short answer
Short answer: Maintain versioned ResponseSpecifications (v1ResSpec, v2ResSpec) and run both against the live API during the migration window. Tag v1 tests with a custom annotation and track them in CI. When v1 traffic drops to zero and the sunset date arrives, delete the tagged tests with a tracked ticket.
Detail
Backwards-compatible changes (adding optional fields, new endpoints, changed defaults) should not require immediate test updates — existing tests should still pass. Breaking changes (removed fields, changed types) require a versioned deprecation strategy.
ResponseSpecification per version:
ResponseSpecification v1ResSpec = new ResponseSpecBuilder()
.expectBody("id", notNullValue())
.expectBody("name", notNullValue())
.build();
ResponseSpecification v2ResSpec = new ResponseSpecBuilder()
.expectBody("id", notNullValue())
.expectBody("name", notNullValue())
.expectBody("fullName", notNullValue()) // v2 addition
.expectBody("createdAt", notNullValue())
.build();
Running both suites in CI against the same API endpoint:
- v1 tests must pass: proves backwards compatibility is maintained
- v2 tests added as the new contract: proves new features work
- v1 tests deleted at sunset: tied to a Jira ticket with the deprecation date
Additive-only tests handle most backwards-compatible changes: new assertions for new fields are added to new tests; existing tests are not modified. A test that asserts body("newOptionalField", ...). would fail against v1 — guard it with version detection or put it only in v2 test classes.
// EXAMPLE
// Version-tagged test
@Tag("v1") @Tag("deprecated-2026-Q3")
@Test
void getUserV1_returnsNameAndEmail() {
given(reqSpec).when().get("/api/v1/users/1")
.then()
.spec(v1ResSpec)
.body("name", notNullValue())
.body("email", notNullValue());
// No fullName assertion — v1 doesn't have it
}
// v2 test — added alongside v1, not a replacement until sunset
@Test
void getUserV2_returnsFullName() {
given(reqSpec).when().get("/api/v2/users/1")
.then()
.spec(v2ResSpec)
.body("name", notNullValue())
.body("fullName", notNullValue())
.body("createdAt", notNullValue());
}
// CI pipeline — runs both in parallel; v1 must stay green during deprecation window
// mvn test -Dgroups="v1,v2" (TestNG) or -Dtags="v1 | v2" (JUnit 5)