Faster deliveries, less bugs - automated tests for the win

As apps continuously evolve it’s becoming harder to keep track of all the internal dependencies and what part influences the other, which makes it even more difficult to test all the required scenarios manually.

Once you reach the point when you spend disproportional amount of time manually testing features that were already implemented before to make sure new features won’t break the current state of the app, it’s right time to start automating your test workflow.

Automatic testing provides great benefits because once you’ve written such test it will automatically test the code for you continuously again and again.

Let me outline common benefits you are gonna get when integrating tests into development workflow.

Benefits of automated testing

  • massive time savings
  • faster deliveries
  • less mundane work and tedious tasks
  • happier developers
  • more reliable, consistent and less bug-prone code

When to write automated tests

There’s no strict rule telling you that you must write tests or outlining how many tests or what code coverage you should aim for. That decision is completely up to you.

When taking in account the fact that large portion of developer’s job is to debug code and making sure the newly develop feature did not break other functionality I highly recommend to write tests at least for the business critical functionality.

At the end of the day it’s still about the cost / benefit aspect. What other criteria I’d consider are whether the project is a long term project or just a prototype or an MVP. I can image in the case of an MVP which is funded externally and the resources are limited to prioritise app features in favour of writing tests. On the other hand in case of already functioning, long term, continually developed project I’d say automated testing is a must.

Types of tests

There are various types of tests and each type serves for different use case. The use case reflects the scope of what the test is testing.

  • Unit tests
  • Integration tests
  • E2E (UI) tests

Now what are the typical characteristics of each of these groups?

Unit tests

From the granularity point of view unit tests fit into category of testing smallest portions of code. You can think pure functions or class methods. How they distinquish from integration tests is they are isolated and thus don’t depend on external dependencies or sources like database or filesystem, which ensures they are also fast and deterministic. If an external source is required, mocks are utilised for that.

Short note on test determinism - for the test to be deterministic it means that it yields the same result every time and the only time the test fails is when the tested code changes. It’s tightly related to flake tests which is a result of non-deterministic tests which might fail not because the code changed but because of an external dependency that failed or time-outed (DB connection, filesystem I/O operation). You want your tests to be as deterministic as possible to avoid flake tests which consume time to be retried.

How to write a unit test for a function that depend on an external source? Here comes the mock, which is a surrogate dependency that act like the real dependency (has the same interface) but mocks the data source with hardcoded, deterministic data.

Integration tests

When it comes to testing larger portion of functionality or how several units of code integrate together it’s integration tests that handle such task. Unlike unit tests they don’t mock external dependencies but use real dependencies like database connection or a 3rd party API.

A typical use for an integration test would be a service that fetches data from an API, transforms the data writes into a database or vice versa, reads data from a database and sends the data via a POST request to the API.

The tests being dependant on a real data source bears a logical consequence of the tests being slower, less deterministic and hence more prone to flake tests. Developers should also bear in mind that setting up a CI/CD test environment is a bit more challenging as you have to incorporate starting a database server and seed data into it.

E2E (UI) tests

So far we’ve covered unit and integration tests which are both responsible for testing the code from the developers point of view because they interact with the low level application code not accessible to the end user. E2E tests present a way how to do exactly that - to test the application from the point of end user by simulating the interactions a real user would normally do.

An example of such test would be a scenario when a user clicks on a product card buy-button and then we verify that a message saying “product was successfully added to cart”.

Because the test is directly interacting with the application UI, this sort of tests is often called UI tests.

They are great to accompany existing unit and integration tests to make sure even the top-level layer (UI) of application works correctly. It helps to detect cases when integrations tests are passing but the UI is broken somehow.

However testing the UI comes with a price of slowness and less deterministic behaviour as E2E tests are the most complex test to run from the 3 outlined types.

The question is what ratio of the types of tests should we aim for. The answer lies in the test pyramid.

Test pyramid

The test pyramid recommends us a ratio between the individual test groups according to their speed and tendencies to flakiness. Let me remind you this is just a theoretical recommendation which is good to follow but it should not be strictly enforced at any cost.

In any case the tests should practically serve you to make your development more efficient. If your application is heavily UI dependent then it’s no problem to introduce larger amount of UI tests because it justifies the means. On the other hand if it wouldn’t make sense to write senseless unit tests, it’s better to rather start implementing integration tests right off the bat.

Conclusion

We’ve covered what makes automated testing so useful and oftentimes necessary, various automated tests types and strategies and also when it’s beneficial for you to start writing automated tests. So what are you waiting for? Let’s write your first automated test.