Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Unit Testing Part 3 - Integration Testing

DZone's Guide to

Unit Testing Part 3 - Integration Testing

In the third entry in our look at unit testing, we'll explore integration testing. Learn what integration testing is, with a sweet example using candy, and see integration testing should happen.

· Integration Zone
Free Resource

Share, secure, distribute, control, and monetize your APIs with the platform built with performance, time-to-value, and growth in mind. Free 90 day trial 3Scale by Red Hat

Image title

As I wrap up this series on unit testing, I will focus on integration testing. To recap, the first article focused on basic unit testing against a POJO class. The second article took things a step futher and introduced testing using mock and stub objects. With these two items in place, a developer should be able to write tests that fully cover the code that has been written, validating the functionality that is expected.

However, in taking this approach, there has not been a test written to make sure connectivity to the real data source can be verified. That is where integration comes into play.

What is Integration Testing?

For the purposes of this article, integration testing refers cases where the system/class under test requires interaction with an external element. Common examples include:

  • Database connection/data

  • Network connectivity

  • An external system (like a queue or a mail server)

  • Read/write file(s) or perform other I/O operations

Candy Category Database Example

Continuing to use a Candy-theme with my examples, let's consider a CandyRepository class, which has a method to return a list of Candy categories. The getAllCandyCategories() method could resemble something as listed below:

public List<CandyCategory> getAllCandyCategories() {
return template.queryForList("SELECT id, name FROM category ORDER BY id ASC");
}

Let's assume the query returns data listed as shown below:

ID Name
0 Gum
1 Candy Stick
2 Chocolate
3 Gummy
4 Jawbreaker
5 Retro

Assuming we want to make sure the Candy category list always contains these items, only these items, using the specified ID's, a test could be written using JUnit as shown below:

@Test
public void testValidateCandyCategories() {
List<CandyCategory> categoryList = candyRepository.getAllCandyCategories();

assertEquals(categoryList.size(), 6);
assertEquals(categoryList.get(0).getName(), "Gum");
assertEquals(categoryList.get(1).getName(), "Candy Stick");
assertEquals(categoryList.get(2).getName(), "Chocolate");
assertEquals(categoryList.get(3).getName(), "Gummy");
assertEquals(categoryList.get(4).getName(), "Jawbreaker");
assertEquals(categoryList.get(5).getName(), "Retro");
}

The test above will validate the size of the list is exactly six elements and that the ID's match what we are expecting. Again, this is a simple example to illustrate how we can perform the test.

When Should the Integration Test Fire?

A common practice is for unit tests to be ran at check-in so that the developer has insight into any errors or issues with the unit tests. Since integration tests are to validate connectivity/configuration at a different level, they are not typically ran at the same time as the unit tests. Instead, they are executed as part of the merge or deployment process.

As a result of this position in the deployment lifecycle, it is possible to use Maven to execute the integration tests using the Surefire plug-in. Using our example above, the plug-in could be configured as shown below:

<build>
<plugins>
    <plugin>
        <artifactId>maven-failsafe-plugin</artifactId>
            <version>2.19</version>
            <dependencies>
            <dependency>
               <groupId>org.apache.maven.surefire</groupId>
                    <artifactId>surefire-junit47</artifactId>
                    <version>2.19</version>
                </dependency>
            </dependencies>
            <configuration>
            <groups>sample.CandyRepositoryTest</groups>
            </configuration>
            <executions>
            <execution>
                <goals>
                    <goal>integration-test</goal>
                    </goals>
                    <configuration>
                    <includes>
                        <include>**/*.class</include>
                        </includes>
                    </configuration>
               </execution>
            </executions>
        </plugin>
    </plugins>
</build>

As a result, when the integration-test goal is fired, the output would resemble what is shown below:

-------------------------------------------------------
 T E S T S
-------------------------------------------------------
Running sample.CandyRespositoryTest
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.085 sec

Results:

Tests run: 1, Failures: 0, Errors: 0, Skipped: 0

[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 1.967 s
[INFO] ------------------------------------------------------------------------

Continuous Integration tools like Bamboo or Jenkins could further automate this process as well.

Conclusion

This series is intended to be a high-level overview of unit testing, including an introduction to integration testing. The key point I wanted to bring forward is to make sure that unit tests are written to focus on the system/class under test.

When external data is required for the tests, it is tempting (and quick) to call the core repository classes to get real data from the database, but I always recommend using mock/stub data instead. That's not to say that database connectivity (as an example) should be ignored, as that is where integration tests come into play.

Have a really great day!

Discover how you can achielve enterpriese agility with microservices and API management

Topics:
unit test ,integration test ,java ,integration

Published at DZone with permission of John Vester, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}