Integration testing best practices

Starting with integration tests is not always the easiest path.

Find within this article all the keys you need to have a clean start with them.

Start simple

In the developing world, the best way to fail is to try to achieve the perfection from the start as you will end up wasting too much resources on unnecessary things.

Instead, you should seek for the essential to keep the simplest system answering the need and while testing this is the same so you should keep it in mind while adding integration tests to a project.

Start by the acceptance

The first question to ask yourself is if you need integration testing in the first place as adding a new layer of testing and maintaining it is some extra work.

For a small project or small companies with limited resources it is a key point to determine whenever your testing strategy is viable on the long run.

In that context the test to prioritize might be more the acceptance ones which are making sure everything is working well the level from the user.

Then if the project grow and the need for integration tests and testing between components appears then at that time it would be appropriate to start them.

It all starts with the Big bang

One of the most complex question for a beginner dealing with integration tests is often which strategy to pick.

If your program is still small and you don’t know how to answer this question then I would advise you to go for the big bang strategy.

While this testing strategy is often described as the less powerful it has its own advantages as it is simple to setup and cheaper to maintain which makes it great for a new comer or a project with limited resources.

Keep them black boxed

Test fragility is highly related to one thing, tests heavily coupled with the code base.

This is why it is key to adopt the right tools and principle from the start to reduce the chances for that to happen and make sure your test are black boxed.

Write the test before the code

To prevent testing the code the easiest way to go is to write them before writing any code.

This is for a simple reason if the code is not implemented yet then you cannot do the mistake of implementing your own code and you will have to be focused on the expectations concerning the application.

Also this has another advantage, to test some code you have to first make sure this one has been designed to be tested and by writing the tests first you will have from start to have testable code.

Base yourself on the acceptance criteria

Another great way to make sure you are not testing the implementation but expectations is to use the acceptance criteria as base for your tests.

A well-formed acceptance criteria is always composed of three parts inspired from the AAA framework, which eases the test implementation:
Arrange: That state aims to describe the initial state from the test to make sure it is reproducible.
Act: This part describes which logic from the application needs to be executed in the test.
Assert: That last step verifies that the final result matches what was expected.

Readability is king

When a test fails it always means the developer in charge will have to make a decision to either correct the test or the code.

This is why it is essential for anyone to be able to get the context from the test fast to make the right decision understanding the full context from that specific test.

Follow the AAA framework

The AAA framework is a way to organize test to make sure they are always complete.

However, it is also a great way to increase their readability too as the reader will always know what to expect and in which order.

That is why it is important to follow this structure not only in the acceptance criteria but also inside the test.

A way to go further with this is by using Gerkhin inside your tests with tools such as cucumber.js for Javascript or behat for PHP. That way your test can even become resources readable by non technical people.

Use generators when needed

While over-engineering is often a trap developers fall into when writing the business logic under-engineering is often waiting them while writing the testing code.

Remember that the right solution is always to not fall into the extremes even if the natural human behavior pushes us to the other extreme to solve an issue.

Generators are a great way to achieve this balance as they encapsulate the entities creation and relationships between them.

This offers an way to easily enhance the test without having to spend hours refactoring while at the beginning the logic inside the generators does not have to be complex which make them not that expensive to start with.

Isolating is mandatory

While testing it is important to always provide the same output for the same input for a trivial reason, it ease debugging.

To achieve this stability isolation of the tests from one another but also from the outside world is necessary.

Mock the external requests

Today most of applications are communicating with each other which makes testing testing in a full black box environment impossible.

Instead, you should mock any external request that goes out of the software brick you are currently testing to not have to setup the entire SAAS.

This will also allow you to be able to control third-party APIs which are totally out of your control and guaranty a constant and reliable response.

Reset the environment

While inside an acceptance criteria the elements to reset should be indicated, a less error prone way is to make sure than the environment resets between each test provide that way isolation.

For that in the set up and the tear down method from your tests it is a common practice to add some logic to reinitialize the environment.

For a database, that could be through launching a transaction before the test and cancelling it after.

For the HTTP request, that would be by adding a mock on the client and removing it at the end.

For global variables, it is important to save the state from the variables to reset them to the same state after the test.

As you might saw it the important is to leave the environment as you found it, clean.

Automated testing is not all

Automated tests are only able to ensure the absence of certain bugs and cannot make sure your code is free of bugs.

Due to that testing will always let bugs pass into production even if it reduce greatly the number of them reaching that point.

This is why it is impact to still have some processes to detect bugs in production fast and handle them quickly.

Monitor to react fast

There is no secret, he best way to react fact to an issue is to detect it early and that exactly what we are doing with automated tests.

However, when they fail we need a safety net which need to be bulletproof and that is exactly the definition of monitoring.

Monitoring is observing

Monitoring is basically observing the behavior of the application and raise awareness when some events are occurring as such as a critical errors, a latency, etc.

For that it is possible to use tools as such as Sentry to filter the data being sent by the application and keep only the important ones.

Logs are your guide

While monitoring not all bugs will end up with a crash of the application easy to detect.

For that reason you should always add some logs inside your code to be able to trace back the events that lead to that bug and gain time investigating the issue.

Control crashes

Even if it cool to see your application crashes within seconds using monitoring, this is a scenario you should avoid at all costs as it damage your product reputation.

Instead, you should try to use a static analyzer tool to handle every possible possibility and return a default value matching the right type while logging the scenarios that should be impossible to reach to monitor them easier.

Do not forget the users

An excellent way of finding indirect problems such as an interface blocking the users to go further or a button not working is to monitor the behavior from users.

That way you will be able to identify their pain points and fix them.

Keep some manual tasks

While manual tests can be seen as a total waste of time it is instead really useful to keep some.

This is due to that fact automated tests cannot see more than what they have been designed for whereas a human can easily notice if something is off even if it is outside of the scope.

That way we are able to still have a fresh view on the application in case we are missing something into our automated process.

Join my newsletter

Never miss a single article and receive a free ebook “Bug hunting for small companies”.


Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *