A common question that pops up now and again is how to configure REST Assured logs to be written to disk instead of printed to the console. The intention of this blog post is to demonstrate how this can be achieved.
But first let’s look at how to use logging in REST Assured:
Logging to Console
REST Assured has something called a Request- and ResponseSpecification and you log the contents of these individually. This is why you often see code like this:
given().
log().all().
queryParam("firstName", "John").
queryParam("lastName", "Doe").
when().
get("/greet").
then().
log().all().
statusCode(200).
body("greeting", equalTo("Greetings John Doe"));
The first call to log().all()
says that we want to log everything in the request specification and the second call to log().all()
instructs REST Assured to log everything in the response specification (after the call has been made). The results can look like this:
Request method: GET Request URI: http://localhost:8080/greet?firstName=John&lastName=Doe Proxy:Request params: Query params: firstName=John lastName=Doe Form params: Path params: Headers: Accept=*/* Cookies: Multiparts: Body: HTTP/1.1 200 OK Content-Type: application/json;charset=utf-8 Content-Length: 98 Server: Jetty(9.3.2.v20150730) { "greeting": "Greetings John Doe" }
We can also decide not to log the request specification at all and only log the response body like this:
given().
queryParam("firstName", "John").
queryParam("lastName", "Doe").
when().
get("/greet").
then().
log().body().
statusCode(200).
body("greeting", equalTo("Greetings John Doe"));
which will log this to the console:
{ "greeting": "Greetings John Doe" }
Note that by default the body is pretty-printed if it’s in a format that REST Assured understands (such as XML, JSON or HTML). You can easily disable this though:
given().
queryParam("firstName", "John").
queryParam("lastName", "Doe").
when().
get("/greet").
then().
log().body(false).
statusCode(200).
body("greeting", equalTo("Greetings John Doe"));
which will return the body as is:
{"greeting":"Greetings John Doe"}
This is all fine, but what if you don’t want to log to the console but instead logging to a file?
Logging to a File
REST Assured comes with a lot of configuration options. By default it provides sane defaults but you can customize a lot of things in REST Assured if required. One of the things you can customize is how logging behaves using the LogConfig class. The LogConfig
allows you to specify a default java.io.PrintStream
that is used for logging when calling e.g. log().all()
. If you haven’t specified a PrintStream
explicitly then REST Assured will default to the PrintStream
defined by System.out
, i.e. it’ll print the logs to the console. But let’s see how we can change this to write a file instead:
try (FileWriter fileWriter = new FileWriter("/tmp/logging.txt");
PrintStream printStream = new PrintStream(new WriterOutputStream(fileWriter), true)) {
RestAssured.config = RestAssured.config().logConfig(LogConfig.logConfig().defaultStream(printStream));
given().
log().all().
queryParam("firstName", "John").
queryParam("lastName", "Doe").
when().
get("/greet").
then().
log().all().
statusCode(200).
body("greeting", equalTo("Greetings John Doe"));
}
This will log everything to the file /tmp/logging.txt
. Note that in this example we’re using the WriterOutputStream class from Apache Commons IO.
Using a JUnit Rule
Typically you probably want to configure the use of file logging once and then have it done with. One way to do this would be to create a Rule in JUnit4 or an extension in JUnit 5. Here we’re going to explore the first option and create a custom JUnit rule. It may be defined like this:
package io.restassured.itest.java.support;
import io.restassured.RestAssured;
import io.restassured.config.LogConfig;
import io.restassured.config.RestAssuredConfig;
import org.apache.commons.io.output.WriterOutputStream;
import org.junit.rules.TestWatcher;
import org.junit.runner.Description;
import java.io.*;
public class WriteLogsToDisk extends TestWatcher {
private final String logFolder;
private PrintStream printStream;
private LogConfig originalLogConfig;
public WriteLogsToDisk(String logFolder) {
File dir = new File(logFolder);
if (!dir.exists()) {
//noinspection ResultOfMethodCallIgnored
dir.mkdirs();
}
if (logFolder.endsWith("/")) {
this.logFolder = logFolder.substring(0, logFolder.length() - 1);
} else {
this.logFolder = logFolder;
}
}
@Override
protected void starting(Description description) {
originalLogConfig = RestAssured.config().getLogConfig();
FileWriter fileWriter;
try {
fileWriter = new FileWriter(logFolder + "/" + description.getMethodName() + ".log");
} catch (IOException e) {
throw new UncheckedIOException(e);
}
printStream = new PrintStream(new WriterOutputStream(fileWriter), true);
RestAssured.config = RestAssured.config().logConfig(LogConfig.logConfig().defaultStream(printStream).enablePrettyPrinting(false));
}
@Override
protected void finished(Description description) {
if (printStream != null) {
printStream.close();
}
if (originalLogConfig != null) {
RestAssured.config = RestAssuredConfig.config().logConfig(originalLogConfig);
}
}
}
What this rule does is to create a log file for each test case in the given file. Let’s see how it can be used:
public class LoggingToDiskTest { @Rule public WriteLogsToDisk writeLogsToDisk = new WriteLogsToDisk("/tmp/rest-assured-logs"); @Test public void example1() { given(). queryParam("firstName", "John"). queryParam("lastName", "Doe"). when(). get("/greet"). then(). log().all(). body("greeting", equalTo("Greetings John Doe")); } @Test public void example2() { given(). queryParam("firstName", "Jane"). queryParam("lastName", "Doe"). when(). get("/greet"). then(). log().all(). body("greeting", equalTo("Greetings Jane Doe")); } }
Now all calls to log()
will be logged to disk. In this case two files will be generated in the /tmp/rest-assured-logs
folder, example1.log
and example2.log
which contains the response logs for each respective test. It only contains the response logs in this example since we’ve chosen not to add log()
to the RequestSpecification
. There’s of course room for improvement to the WriteLogsToDisk
rule, for example we could automatically remove files which are empty (i.e. no REST Assured logs where recorded for a particular test). You can have a look at an example test here and the code for WriteLogsToDisk
here.
Conclusion
As you can see REST Assured is quite flexible and you can configure it to achieve most use cases, logging to disk being one example. If you haven’t done so already, feel free to try it out. Happy testing!
8 thoughts on “Logging to Disk with REST Assured”
Surprised to see no comments so far on this most useful necessity for testing ( logging test results) . I used loggging on disk files when testing soap services using SoapUI and definitely going to use this when building my framework on Restapi. Thanks for sharing.
Thanks for your comment 🙂
How to configure REST Assured drop all requests and responses with the below format at console when run Junit test cases
[main] DEBUG org.apache.http.headers – >> Connection: Keep-Alive
Hi friend,
This is very useful in API testing. Thank you for sharing. I also have a question in rest-assured. Is there a way to add something (like \n) between request and response? Thank you!
For example:
Request URI: http://52.74.68.90:9100/advertiser/signup/orm
Request method: POST
Headers: Accept=*/*
Content-Type=application/json; charset=UTF-8
Request params:
Query params:
Form params:
Path params:
Multiparts:
——I want to add a blank line here to distinguish the request and response
HTTP/1.1 201 Created
{“username”:”ellen_autoadvsignup1″}
BR.
TavisD
Hi Travis,
This blog is not the right forum for asking questions. Please use the mailing-list instead.
Regards,
/Johan
Hi, can you tell me how you decided this problem?
I want too do this, make line between request and response.
Thanks for sharing. Its really helpful.