Test APIs

Before release your application to the public world, you have to make sure it works as expected.

Testing is the most effective way to prove your codes correct.

Test driven development

In the XP and Agile world, lots of developers are TDD advocate, and use it in daily work.

The basic flow of TDD can be summaries as:

  1. Write a test first, then run test and get failure, failure info indicates what to do(You have not written any codes yet).

  2. Code the implementation, and run test again and again, untill the test get passed.

  3. Adjust the test to add more features, and refactor the codes, till all considerations are included.

But some developers prefer writing codes firstly and then write tests to verify them, it is OK. There is no policy to force you accept TDD. For a skilled developer, both are productive in work.

We have written some codes in the early posts, now it is time to add some test codes to show up how to test Spring components.

Spring provides a test context environment for developers, it supports JUnit and TestNG.

In this sample application, I will use JUnit as test runner, also use Mockito to test service in isolation, and use Rest Assured BDD like fluent APIs to test REST from client view.

A simple POJO test

A classic JUnit test could look like this.

public class PostTest {

    public PostTest() {
    }

    @BeforeClass
    public static void setUpClass() {
    }

    @AfterClass
    public static void tearDownClass() {
    }

    private Post post;

    @Before
    public void setUp() {
        post = new Post();
        post.setTitle("test title");
        post.setContent("test content");
    }

    @After
    public void tearDown() {
        post = null;
    }

    /**
     * Test of getId method, of class Post.
     */
    @Test
    public void testPojo() {
        assertEquals("test title", post.getTitle());
        assertEquals("test content", post.getContent());
    }

}

@BeforeClass and AfterClass method must be static, these will be executed after the test class is constructed and before it is destroyed.

@Before and @After will be executed around a test case.

A test case is a method annotated with @Test.

Another annotation we always used is @RunWith, such as @RunWith(SpringJUnit4ClassRunner.class), which will prepare specific test context for Spring tests.

Run the test in command line.

You could see the following output summary for this test.

Post is a simple POJO, does not depend on other dependencies.

Test Service

BlogService depends on PostRepository, but most of time, we only want to check if the business logic and flow correct in the BlogService and assume the dependency PostRepository are always working as expected. Thus it is easy to focus on testing BlogService itself.

Mockito provides the simplest approaches to mock the dependencies, and setup the assumption, and provides an isolation environment to test BlogService.

Isolate dependencies with Mockito

Mocks PostRepository, when invoke methods of PostRepository, return the dummy data we assumed. Mockito gives us a simple way to complete the assumption progress.

Create a MockDataConfig configuration class in test package.

We create mocked PostRepository in this configuration.

Create MockBlogServiceTest for BlogService, used MockDataConfig to load configurations.

PostRepository and CommentRepository are mocked object defined in the MockDataConfig.

Add a test method in MockBlogServiceTest.

In the above test, asserts id value of the returned post is 1L.

Have a look at MockDataConfig, when calls save method of PostRepository and return a dummy post instance which id is 1L.

We can also test if the exception threw as expected in the MockDataConfig.

Run the test in command line tools.

You will see the test result like.

Integration test

We have known BlogService works when we mocked the dependencies.

Now we write a test to check if it works against a real database.

In the @Before method, all Post data are cleared for each tests, and save a Post for further test assertion.

The above codes are similar with early Mockito version, the main difference is we have switched configuraitons to a real database. Check the @ContextConfiguration annotated on BlogServiceTest.

Run the test.

The test result should be shown as below.

Test Controller

Spring provides a sort of mock APIs to emulate a Servlet container environment, thus it is possible to test MVC related feature without a real container.

Use MockMvc with mocked service

MockMvc does not need a Servlet container, but can test most of the Controller features.

Like the former MockBlogServiceTest, we can mock the controller's dependencies, thus is no need to load Spring configurations.

In the setup method, mvc = standaloneSetup(postController) is trying to setup a MockMvc for controller. The test codes are easy to understand.

MockMvc with a real database

We changed a little on the above tests, replace the mocked service with the real configurations. Thus the tests will run against a real database, but still in mock mvc environment.

In this test class, the Mockito codes are replaced with Spring test, and load the configurations defined in this project. It is close to the final production environment, except there is not a real Servlet container.

Test REST API as the client view

OK, now try to verify everything works in a real container.

RestTemplate is use for interaction with remote REST API, this test acts as a remote client, and shake hands with our backend through REST APIs.

BasicAuthRestTemplate is a helper class to process BASIC authentication.

To run this test successfully, you have to configure maven-failsafe-plugin to set up a Servlet container.

  • Start up container before test is running

  • Shutdown the servlet container after the test is completed

    org.apache.maven.pluginsmaven-surefire-plugin2.19truetrue**/*IntegrationTest*

Excludes the IntegrationTest in the maven-surefire-plugin.

org.apache.maven.pluginsmaven-failsafe-plugin2.12.4**/*IntegrationTest*integration-testintegration-testverifyverify

Filter the IntegrationTest in the maven-failsafe-plugin. Here I configured jetty as Servlet container to run the test.

org.eclipse.jettyjetty-maven-plugin9.3.7.v20160115108005STOP/angularjs-springmvc-samplestart-jettypre-integration-teststopstart0truestop-jettypost-integration-teststop

In the pre-integration-test phase, check if the jetty is running and starts up it, in post-integration-test phase, shutdown the container.

Run the IntegrationTest in command line.

In the console, after all unit tess are done, it will start jetty and deploy the project war into jetty and run the IntegrationTest on it.

As you see in the console, after the test is done, it is trying to shutdown jetty.

Rest Assured

Rest Assured provides BDD like syntax, such as given, when, then, it is friendly for those familiar with BDD.

This test is also run as client, and interacts with backend via REST API.

The above Rest Assured sample codes are available in the Spring Boot version, check out the codes and experience yourself.

It also includes a simple JBehave sample, if you are a JBehave user, you maybe interested in it.

Source Code

Check out sample codes from my github account.

Or the Spring Boot version:

Read the live version of these posts from Gitbook:Building RESTful APIs with Spring MVC.

Last updated

Was this helpful?