Full-fledged backend architecture from our previous article. Source: Author. |
How to build a full-fledged backend architecture in Java - Part II
In the
previous article you learned how to build a full-fledged backend architecture
in Java. In this article, you’ll learn how to test the functionality you just
built.
Testing
As
experienced software developers, it is indispensable for us to create unit
tests for every single functionality we write. Nonetheless, for the present
case we are facing two challenges:
1. How to call our API? – We need a
mechanism to simulate frontend calling our API, send the proper parameters in
the request, catch the response and validate its correctness.
2. How to fake the response of our
client’s API? – We’re able to call an external service, but… it is not there.
Thus we need an instrument to return a fake/mocked response, once the call is
executed.
Introducing RestAssured
RestAssured
is a Java library that allows us to easily test our REST endpoints by
simulating frontend calls to our API. It also provides the functionality to
assert the validity of the responses.
RestAssured
allows us to perform a call to our endpoint and validate that the response we
get from it is the expected one.
They key methods are:
ü Http Methods: get(), post(), put(), delete(),
options(), patch(), head() Performs a call to the specified endpoint using the selected HTTP
Method.
ü Then() – Everything that comes after
this method is an assertion. We can validate for instance:
ü statusCode() – HTTP Status code of
the response
ü body() – Check the contents of the response. We can check individual fields in the following manner:
.body("id", notNullValue())
.body("id",5)
.body("status",equalTo("SUCCESS"))
Note that we use RestAssured in conjunction with org.hamcrest.Matchers.
With the help of RestAssured we are able to call our own API and thereby solve problem #1. What about problem #2?
Introducing Restito
Restito is
a library that:
ü Mimics rest server behavior
ü Records HTTP calls to the server
ü Performs verification against
happened calls
According
to the documentation:
“Restito
sets up a StubServer instance which responds to your application's Calls based
on defined Stubs. A stub makes some Action when Condition is satisfied.”
Colloquially,
we can mock the response we’ll get from the external service. To set restito up,
we follow the next procedure:
1. Set up a Stub server, which will be
listening to a specific port.
2. Add the conditions that the request
should meet. These can be:
a. Match() – Here you can specify the
endpoint, the HTTP method to which the server will respond, and the request
including body and headers.
b. Then() – Allows us to create the
expected server response, including HTTP status and body of the response.
Perfect! Thanks
to Restito and RestAssured you can fully test your endpoint. Now, let’s get our
hands on the code.
Code!
Now we’ll
create a new class for our tests. Let’s call it: UsersValidationsTest.java
We need to
annotate this class properly and Spring provides several options for this
purpose. Some of these options are:
ü @SpringBootTest – Used to perform
complete integration tests with all the elements of the backend. The
@SpringBootTest annotation tells Spring Boot to go and look for the main
configuration class (one with @SpringBootApplication for instance), and use
that to start a Spring application context. [Spring Guides]
ü @WebMvcTest – Performs tests on the
web application layer. Generally used to test controllers without
calling internal services. The latter are mocked through the annotation
@MockBean
To make our
test more comprehensive, we’ll create an E2E test that will test all the
layers of our architecture. Hence, the annotation @SpringBootTest is the
appropriate one in our case.
Our class now looks as follows:
UsersValidationsTest.java
@RunWith(SpringRunner.class) @SpringBootTest(classes = RestTestDemoApplication.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) public class UsersValidationsTest {
}
Next step
is to set restito up. From the examples, we need to create the stub server,
start it, and stop it after the test. For this purpose, we’ll create an object
called externalServiceServer and start/stop it using the annotations
@BeforeClass and @AfterClass, respectively.
protected static StubServer externalServiceServer;
@BeforeClass public synchronized static void start() { externalServiceServer = new StubServer(8000).run(); } @AfterClass public static void stop() { externalServiceServer.stop(); }
In regard
to the test itself, there are two possible scenarios:
ü Either the username exists, and the
API returns HTTP Status 302
ü Or the username is not registered,
and the API returns HTTP Status 404.
For the
scope of this tutorial we’ll test only case number one.
We’ll
create our test function. Let’s name it checkExistingUsername. Inside it, we
have to:
1. Create the object for the expected
response from the external service.
2. Finish setting restito up by
executing step #2 from the introduction to Restito.
3. Execute the API and validate the
response.
The final @Test method will look as follows:
@Test public void checkExistingUsername() throws JsonProcessingException { //1. Create the object for the expected response from the external service. String username = "14c4b06b824ec593239362517f538b29"; UserFeignClientResponse externalServiceResponse = new UserFeignClientResponse("c4ca4238a0b923820dcc509a6f75849b", "Foo User", "Foo", new Date(), username); //2. Finish setting up restito ObjectMapper mapper = new ObjectMapper(); whenHttp(externalServiceServer).match(Condition.get("/user/get/" + username)) .then( Action.stringContent(mapper.writeValueAsString( externalServiceResponse)), Action.contentType(MediaType.APPLICATION_JSON_UTF8_VALUE), Action.status(HttpStatus.OK_200)); // 3. Execute the API and validate the response. RestAssured .given() .contentType(MediaType.APPLICATION_JSON_UTF8_VALUE) .when() .get(path + "/users/exists/" + username) .then() .statusCode(HttpStatus.FOUND_302.getStatusCode()); }
Now, the moment of truth has come. Let’s test our API:
Figure 1. Tests passed! |
Aaaaaaaaand
THERE YOU GO! Our API and its architecture work as expected.
You can download the code for this tutorial from Github!
In this tutorial, you learned how to build and test a robust backend architecture, which respects the separation of concerns and makes your code cleaner, easier to understand and maintain.
Now it’s your turn to start applying this knowledge to your personal and corporate projects.
Stay tuned
for more in-depth tutorials! Hasta la
vista!
Comments
Post a Comment