Spock in Cortilia: integration test overview
“People also underestimate the time they spend debugging. They underestimate how much time they can spend chasing a long bug. With testing, I know straight away when I added a bug. That lets me fix the bug immediately, before it can crawl off and hide. There are few things more frustrating or time wasting than debugging. Wouldn’t it be a hell of a lot quicker if we just didn’t create the bugs in the first place?“
Martin Fowler
1. Overview
Integration testing plays an important role in the application development cycle by verifying the end-to-end behavior of a system.
In this article, we will analyze the importance of integration tests and we will see a concrete example realized in Cortilia.
2. What is integration testing?
Sometimes there is not a clear distinction between what is an integration test and what is a unit test.
My basic rule of thumb is that if
- a test uses the database
- a test uses the network
- a test uses an external system (e.g. a queue or a mail server)
- a test reads/writes files or performs other I/O
then it is an integration test and not a unit test.
3. Why Integration Test?
Integration testing is mainly useful for situations where unit testing is not enough. Sometimes you need to have tests to verify that two separate systems (such as database and your app) work together correctly, and that calls for an integration test. As a result, when validating integration test results, you could for example validate a database related test by querying the database to check the database state is correct. Integration tests are “high-level” tests, in which we “take on the clothes” of the user who is actually using the application and try to get a result in response to a certain action. In our testing environment, most of the companies and organization focuses on end-to-end testing. Well end-to-end testing is important but it needs to cover the real use cases. Most of the testers spent 80% of the time finding basic bugs rather than working on the actual use cases.
With the right testing strategy and release plan, in the real world, there is always less time or no time for testing real-time use cases.
Most of the industry and organizations have adapted only to Unit testing and Functional testing. It’s some of the organization that has the Integration testing in the testing life cycle.
4. Advantages
This type of test verifies the functional correctness in the iteration between multiple modules.
Some advantages of Integration Testing:
- Assemble the modules together incrementally;
- Assembling producers before consumers where the verification of the former provides the latter with a flow of control (calls) and a flow of already correct data;
- Assemble all the modules and test the system as a unit (aka “Big Bang Test”);
- Creating the right test gives a precise feedback loop mechanism between both developers and test engineers;
- Tests run faster compared to end-to-end tests;
- Code Coverage is higher and easy to track;
- It does not require the completion of the other module to perform the test, as for the same you can use Stub and Driver.
- Tests are more reliable and easy to isolate the failures;
- Detect interface errors.
- Majorly helps to build real-time use cases during end-to-end testing;
- Integration tests catch system-level issues, such as a broken database schema, mistaken cache integration, and so on.
5. Spock for Integration Test
Cortilia uses Spock aims to be a more powerful alternative to the traditional JUnit stack where it is easy to test even asynchronous processes.
Spock, it’s a Groovy testing framework that offers you all the testing facilities you might need during the full testing lifecycle. It comes with built-in mocking and stubbing and several extra testing annotations created exclusively for integration tests.
Spock doesn’t need special constructs for capturing arguments and creating mocked answers. It uses Groovy closures, which are similar to Java 8 lambda expressions.
Mockito has a limitation with argument matchers. If you use matchers in a method, then all arguments need to have matchers. Spock does not suffer from this limitation, and you can mix and match real arguments with argument matcher.
Spock makes a distinction between stubs and mocks, making unit tests slightly more readable.
Spock presents much more detailed error messages when expected mock invocations are not found.
Finally, Spock provides some logical subdivisions for writing the test called blocks. Using blocks (given, when, then, expect, cleanup) makes more readable tests.
I attached a snippet copied from the official Spock Primer documentation which explains the blocks in more details:
Spock has built-in support for implementing each of the conceptual phases of a feature method.
Feature methods are structured into so-called blocks.
It must have at least one explicit block.
Blocks start with a label and extend to the beginning of the next block or the end of the method.
5. Example
In the previous paragraphs, we have understood the main reasons why it is important to write integration tests and the technologies suggested for their definition.
In this section, I would like to show you a couple of examples realized in Cortilia both were written using the Spock’s framework.
In the first example we have defined tests for customer’s authentication and the second an example of an asynchronous test with Vertex.
example 1
example 2
6. Conclusion
We learned what it means to write integration tests and their importance.
In conclusion, I would like to leave 6 pills that summarize the right mindset that is needed for writing of integration test:
- Requires a Developer with Tester’s attitude.
- Management encouragement to build a strong Test team who would work and think like a tester with development skillsets.
- Test Automation Developers need to think beyond writing tests after the product built but at a very early stage of development.
- Test are written from day one of the development cycles.
- Always recommend writing good tests and every engineer to test their code.
- It is important to be a disciplined programmer who doesn’t deliver tests but delivers robust test suites!
Good “testing” everyone! :)