logo
Interview
Integration Testing Interview Questions
Do you know how to make your components work in harmony?
integrationtesting
Question 1
What is the difference between an integration test and an end to end test?
Integration Test
Tests individual software components to verify the interaction between them and to detect interface defects.

Those tests are, let's say a higher level of existence compared to the unit ones. So once we have all the functionality covered with detailed unit tests, and we know that each of the components works as it should, now its time to test the interaction between them.

It's also appropriate now to set up all the environment around our functionality whether it would be a connection to the database, web service or file system.

Having that in mind, integration tests are much more difficult to write, run much slower regarding the attached resources with which they interact and the level in the codebase from where they are invoked.

Examples:
  • Service method calls two repository methods which get data directly from the database and performs specific processing on the combined outputs.
  • Servlets doPost() method sends all submitted form data to a RESTful Web Service and receives a certain Http Response.

E2E
The highest level of existence in the automated test world is the E2E tests. But the less of those we have, the better. These are manual functional tests adapted to run as automated ones.
Due to that, they are very slow compared to super-fast low-level unit tests. Maintaining them is also a tough and time-consuming task.
They require a plethora of setup and usually need more than one the type of resource to be set up and prepared.

Examples:
  • Logging into the system
  • Logging out of the system
  • Moving from search screen to the details screen by clicking on one of the lists items
  • Launching a batch command with certain input
Integration tests usually take considerably more time to run compared to plain old unit tests.
If we were to put them together under one suite, the time for it to run would increase considerably.

This is not what we want. During development, we would like to run the unit test suite many times an hour quickly. We would run the integration tests just before the commit to make sure we did not break dependent components.

Thus, a separate suite for IT's is highly advised.
Maven, for example, has its phase dedicated to them which runs just after unit tests.
We should strive not to use mocking or the least amount possible in our integration tests.
In general the dependencies of SUT should not be mocked unless we intentionally want to mock a 3rd party webservice or the database call for example. So, if we really have to, we might take advantage of the vanilla Mockito combined with Spring Test or Spring Boot Test.
Unit Test
Unit Test is an automated piece of code that invokes a unit of work in the system and then checks a single assumption about the behaviour of that unit of work.

The traits of a unit test are:
  • Fast - if a unit test is not fast.. there is something wrong because the primary purpose of a unit test is speed. How fast? Usually, a suite of a thousand tests should not take more than 10 seconds to run. Thanks to that, when you are developing a new change, at certain stages, you would just run the whole suite to check if you haven't broken anything.
  • Easily Developed - unit test should be dead simple when it comes to the structure so that the person looking at it instantly knows what is the deal here.
  • Easily Integrated with CI Process - if you haven't got at least a basic suite of unit tests and you are using tools like Jenkins.. well.. it's like buying the most expensive sound system and the listening just to techno music. I don't have anything against techno, but it's not the most sophisticated audio-wise music.. and probably a medium-range option would give the same results. With jazz, classical or rock you could get the full potential of that best audio set. Otherwise, it's just a waste of money.
  • Base ingredient of high-quality code - to be able to cover your system with unit tests (which are readable and maintainable) You need to have good design. Otherwise it would just be hell to create a unit test suite... and even more, hell to maintain it. So if you want to have unit tests, you better take care of the design of your code.
  • Living documentation of the code - commenting the code is something that is not much maintained. The code has been changed ten times, but the comments around are still from the first change and its just misleading. When you have unit tests.. even when you are not sure what a method do you check out the unit tests and see all the logical paths.

Unit Tests DON'T:
  • Hit the database
  • Hit the file system
  • Connect to network
  • Invoke threads
  • Call non-trivial methods of dependent classes

Examples:
  • Calling getInstance() method of a singleton class many times always returns the same object.
  • Factory method returns proper implementation of an interface based on certain input params.
  • Custom Exception has a default, specified error message.
  • Certain enumeration values have a concrete ordinal number.
  • Service method calls a repository method with certain values as params.


Integration Test
Tests individual software components to verify the interaction between them and to detect interface defects.

Those tests are, let's say a higher level of existence compared to the unit ones. So once we have all the functionality covered with detailed unit tests, and we know that each of the components works as it should, now its time to test the interaction between them.

It's also appropriate now to set up all the environment around our functionality whether it would be a connection to the database, web service or file system.

Having that in mind, integration tests are much more difficult to write, run much slower regarding the attached resources with which they interact and the level in the codebase from where they are invoked.

The traits of integration tests are:
  • More difficult to write
  • Run much slower
  • Require a lot of setting up
  • Additional resources required
  • Performance verification

Examples:
  • Service method calls two repository methods which get data directly from the database and performs specific processing on the combined outputs.
  • Servlets doPost() method sends all submitted form data to a RESTful Web Service and receives a certain Http Response.

Maven has the Failsafe Plugin that is designed to run integration tests while the Surefire Plugin is designed to run unit tests.

Maven integration tests lifecycle phases:
  • pre-integration-test for setting up the integration test environment.
  • integration-test for running the integration tests.
  • post-integration-test for tearing down the integration test environment.
  • verify for checking the results of the integration tests.
A common practice is to put your clean-up code at the end of the test.

What it prevents is a full diagnosis of failures as the, possibly, wrong data will not be in the persistent store any more.

Would the data be left as it is after a failure, the developer can examine the problem in much more detail.

So try to initialise a clean-up before each of the persistent layer tests start.
Flickering is a term used to describe randomly failing tests that have a set time out.

When they happen more often, most likely we are missing potentially critical bugs. Not visible to a naked eye they might be deadly in production environment:
  • Wrong configuration of a third-party library
  • Too large transactions
  • Not the latest version of a database driver.

The list might go on and on.
It should be part of any TDD cycling.
As not so obvious, every team should make the integration testing an integral part of their TDD routines.

The normal TDD cycle is strictly attached to a unit test and it seems hard at first to fit in any integration tests into the equation.

Once we think of the first failing integration tests as a sort of watch dog which tells us from higher up where we should be heading with our TDD cycles and when to stop it all starts to come together.

So write a bunch of failing integration tests and then TDD the hell out of the new feature.

Integration tests ideally should sit between a thick layer of unit tests and a small number of end to end tests. Here is an example distribution that could be considered as relevant to most of the projects

Integration tests in general take quite a bit of time so running the entire suite often, might seem like an overkill.
They have to be run for sure just before we commit. Also there should be a CI job that runs them each time a fresh commit is pushed.