There are differing views on Integration tests but here is my typically preferred approach.
I always encourage both developers and testers in my team to have a good understanding of all levels of tests, unit, integration and acceptance tests. However, that being said it’s normally the developers that will update the integration tests while they work on code initially. The testers should be able to read and make changes when they see fit, the key point is communication so everyone in the team feels ownership.
Integration tests should validate that components within the code base are communicating with each other as we would expect. Lets try a simple example:
We have some code that takes a user’s first name as input, validates that the first letter is capitalised, then sends a tweet with the first name in it before finally saving the first name into a database.
Now let’s assume this system has been created in well defined modules:
- a Class that takes a string as input and validates the first letter is capitalised
- a Class that given some text will send a tweet via Twitter
- a Class that given some text will save it to a database
We can check the logic works for each of these individual modules via unit tests. That allows us to cleanly test that they handle lots of possible scenarios relating specifically to their task. The class that validates the first letter of a string is capitalised should have tests to validate it can handle scenarios such as being passed an empty String, or a number instead of text. The unit test gives us re-assurance that that module can perform its specific task well.
What are integration tests are used for is to check that the communication between these modules happens as we would expected. So if I was writing integration tests for our application above I would want to know that once my module has successfully validated the users first name then it should be making a call to the tweet module passing it the validated name. I can pass my validation module a test spy version of the tweet module and assert that it gets called with the valid username being passed. I can then write another integration test to confirm that if I pass an invalid name to my first module, I then assert that it does not call my tweet module.
Likewise we move through the system checking that the modules interact with each other in the expected way. We can replace the instances of the modules it should be interacting with as all we are testing is that the expected modules are being called in different test scenarios. Our unit tests have already confirmed that each individual module can do it’s job so we just need to know that we a re calling them correctly.
- Yes the test doubles that can be utilised as mentioned briefly above are spies, which allow you to confirm that they were called with specific parameters. Stubs can also be used if you need to have parts of the code pass canned responses in order to allow you to test a specific scenario.
Once I was happy that the code’s modules were all unit tested to confirm they perform as expected in isolation at their specific tasks. I would then want integration tests to confirm the flow of my application by verifying the modules communicate with each other in the expected ways depending on the scenario. Finally some end-to-end acceptance tests allow us to check some features that the user wishes to perform on our system.
I hope that helps and hasn’t added more confusion