Introduction
In our previous post, we explored Performance Testing with REST Assured, learning how to measure API performance. Now, we’ll dive into Logging and Debugging, essential techniques for identifying and resolving issues in API tests. This guide is designed for beginners and experienced developers, providing clear explanations and practical examples to master logging and debugging in REST Assured.
Key Point: Logging and debugging in REST Assured help you inspect requests, responses, and errors, making it easier to troubleshoot test failures and ensure API correctness.
What are Logging and Debugging in API Testing?
Logging involves capturing details about HTTP requests and responses, such as headers, bodies, and status codes, to analyze test execution. Debugging uses these logs, along with other techniques, to identify and fix issues in test code or API behavior.
REST Assured provides built-in logging methods to capture request and response details, which can be combined with external tools (e.g., IDE debuggers or logging frameworks) for comprehensive troubleshooting.
Setting Up for Logging and Debugging
REST Assured’s logging features are available out of the box, requiring no additional dependencies. We’ll use the public API https://jsonplaceholder.typicode.com
for examples.
Ensure your pom.xml
includes dependencies for REST Assured and JUnit:
io.restassured
rest-assured
5.4.0
test
org.junit.jupiter
junit-jupiter
5.10.2
test
org.hamcrest
hamcrest
2.2
test
Logs will output to the console by default, but you can configure a logging framework like Log4j for advanced logging.
Logging in REST Assured
REST Assured provides methods like log().all()
, log().ifValidationFails()
, and others to log request and response details. Let’s explore common logging scenarios.
Example 1: Logging Entire Request and Response
Log all details of a request and response to inspect headers, body, and status code.
import io.restassured.RestAssured;
import org.junit.jupiter.api.Test;
import static io.restassured.RestAssured.*;
public class LogAllTest {
@Test
public void testLogAll() {
RestAssured.baseURI = "https://jsonplaceholder.typicode.com";
given()
.log().all() // Log request details
.queryParam("userId", 1)
.when()
.get("/posts")
.then()
.log().all() // Log response details
.statusCode(200);
}
}
Explanation:
log().all()
: Logs the full request (method, URL, headers, query parameters, body) and response (status code, headers, body).- Output appears in the console, showing details like:
Request method: GET Request URI: https://jsonplaceholder.typicode.com/posts?userId=1 Headers: Accept=*/* Response status: 200 OK Response body: [{"id":1,"userId":1,"title":"...","body":"..."},...]
Important: Use log().all()
sparingly in production tests, as it generates verbose output. It’s best for debugging specific issues.
Example 2: Logging Only on Validation Failure
Log details only when a test fails to reduce console clutter.
import io.restassured.RestAssured;
import org.junit.jupiter.api.Test;
import static io.restassured.RestAssured.*;
public class LogIfValidationFailsTest {
@Test
public void testLogIfValidationFails() {
RestAssured.baseURI = "https://jsonplaceholder.typicode.com";
given()
.log().ifValidationFails() // Log request if validation fails
.pathParam("postId", 9999) // Non-existent ID
.when()
.get("/posts/{postId}")
.then()
.log().ifValidationFails() // Log response if validation fails
.statusCode(200); // Intentionally incorrect to trigger logging
}
}
Explanation:
log().ifValidationFails()
: Logs request and response only if the test fails (e.g., status code is not 200).- Since the API returns 404 for a non-existent post, the test fails, triggering logs for both request and response.
- This approach keeps logs clean during successful runs.
Example 3: Selective Logging
Log specific parts of the request or response, such as headers or body.
import io.restassured.RestAssured;
import org.junit.jupiter.api.Test;
import static io.restassured.RestAssured.*;
import static org.hamcrest.Matchers.*;
public class SelectiveLogTest {
@Test
public void testSelectiveLogging() {
RestAssured.baseURI = "https://jsonplaceholder.typicode.com";
given()
.log().headers() // Log only request headers
.header("Custom-Header", "TestValue")
.when()
.get("/posts/1")
.then()
.log().body() // Log only response body
.statusCode(200)
.body("id", equalTo(1));
}
}
Explanation:
log().headers()
: Logs only the request headers (e.g.,Custom-Header: TestValue
).log().body()
: Logs only the response body (e.g., JSON payload).- Other options include
log().parameters()
for query/form parameters orlog().method()
for the HTTP method.
Pro Tip: Use selective logging to focus on specific details, reducing noise and improving readability during debugging.
Debugging in REST Assured
Debugging involves analyzing logs and using additional techniques to pinpoint issues. Common debugging strategies include:
- Inspecting logs for mismatches in request/response data.
- Using IDE breakpoints to pause test execution.
- Extracting responses for detailed validation.
Example: Extracting Response for Debugging
Extract the response to inspect its contents programmatically.
import io.restassured.RestAssured;
import io.restassured.response.Response;
import org.junit.jupiter.api.Test;
import static io.restassured.RestAssured.*;
import static org.junit.jupiter.api.Assertions.*;
public class DebugResponseTest {
@Test
public void testDebugResponse() {
RestAssured.baseURI = "https://jsonplaceholder.typicode.com";
Response response = given()
.log().all()
.pathParam("postId", 1)
.when()
.get("/posts/{postId}")
.then()
.log().all()
.extract().response();
// Debug response details
int statusCode = response.getStatusCode();
String body = response.getBody().asString();
String contentType = response.getHeader("Content-Type");
System.out.println("Status Code: " + statusCode);
System.out.println("Response Body: " + body);
System.out.println("Content-Type: " + contentType);
// Validate
assertEquals(200, statusCode);
assertTrue(body.contains("\"id\": 1"));
assertTrue(contentType.contains("application/json"));
}
}
Explanation:
extract().response()
: Captures the full response for inspection.getStatusCode()
,getBody().asString()
,getHeader()
: Extract specific response details.- Print statements and assertions help debug by showing actual values.
Using Request Specification for Logging
Centralize logging settings with a Request Specification to apply them consistently across tests.
import io.restassured.RestAssured;
import io.restassured.builder.RequestSpecBuilder;
import io.restassured.specification.RequestSpecification;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import static io.restassured.RestAssured.*;
import static org.hamcrest.Matchers.*;
public class LogWithSpecTest {
private static RequestSpecification requestSpec;
@BeforeAll
public static void setup() {
requestSpec = new RequestSpecBuilder()
.setBaseUri("https://jsonplaceholder.typicode.com")
.addHeader("Accept", "application/json")
.log(LogDetail.ALL) // Log all request details
.build();
}
@Test
public void testLogWithSpec() {
given()
.spec(requestSpec)
.pathParam("postId", 1)
.when()
.get("/posts/{postId}")
.then()
.log().all() // Log response details
.statusCode(200)
.body("id", equalTo(1));
}
}
Explanation:
log(LogDetail.ALL)
: Configures the specification to log all request details.spec(requestSpec)
: Applies the specification, including logging, to the test.LogDetail
options includeHEADERS
,BODY
,PARAMS
, etc.
Configuring a Logging Framework (Optional)
For advanced logging, integrate a framework like Log4j to redirect REST Assured logs to a file or custom appender.
Add Log4j to your pom.xml
:
org.apache.logging.log4j
log4j-core
2.23.1
test
org.apache.logging.log4j
log4j-api
2.23.1
test
Create a log4j2.xml
file in src/test/resources
:
Use Log4j in a test:
import io.restassured.RestAssured;
import org.junit.jupiter.api.Test;
import static io.restassured.RestAssured.*;
public class Log4jTest {
@Test
public void testWithLog4j() {
RestAssured.baseURI = "https://jsonplaceholder.typicode.com";
given()
.log().all()
.when()
.get("/posts/1")
.then()
.log().all()
.statusCode(200);
}
}
Explanation:
log4j2.xml
: Configures Log4j to log REST Assured output to the console and a file (logs/rest-assured.log
).- Logs are timestamped and include request/response details.
Tips for Beginners
- Start with log().ifValidationFails(): It’s the most efficient way to log only when tests fail.
- Use Selective Logging: Log specific parts (e.g., headers or body) to focus on relevant data.
- Leverage IDE Debuggers: Set breakpoints in your test code to inspect variables and responses.
- Check API Documentation: Ensure logged responses match expected formats to identify API issues.
Troubleshooting Tip: If a test fails, check logs for mismatched status codes, headers, or body content. Use log().all()
temporarily to capture all details, then refine with selective logging.
What’s Next?
In the next post, we’ll cover Test Reporting, exploring how to generate detailed reports for REST Assured tests using tools like Allure or ExtentReports. Stay tuned for more hands-on examples!