What are Unit Tests, UI Tests, Integration Tests and End-to-End Tests

Test it to find mistkaes

Image for post
Image for post
Photo by Jeremy Bishop on Unsplash

Testing is one of those things in programming that (now we can argue if this is dysfunctional or not) seems to be put on the back burner, or at the end of an entire software development process.

This mentality issue can be tackled through TDD, ATDD or BDD yet even if these aren’t adopted some type of testing is important.

We need to know that our software works, and one way of making sure of this is through Unit testing, UITests, Integration tests or End-to-End testing.

In some cases, programmers spend time testing edge cases and error cases of a function, and forget to test the relationship with the network dependency on which it relies.

What does this all mean?? Read the following article to find out…

Unit testing

Unit tests are so common that you might see familiarity with them requested in job descriptions for software engineers. You might be decoding JSON and need to test the process, using dependency injection to inject services or fully unit test a network service. All of these perform the same essential function; isolate some code and test them as a self-contained unit.

This is relatively simple for something like a basic calculator where you can test an add function through various paths through the code — and what happens when one (or more) parameters are negative. You’ll be testing for the results that you expect, both when things are going well (expected inputs) and for when things go awry (unexpected but possible inputs).

The importance of unit testing can’t be understated, and TDD demands that these are written before the code that the tests are created to check is even produced.

These tests are programatic, so should use the coding principles of avoiding code reuse and they themselves should be isolated, well written and maintainable.

UI testing

Front-end development focuses on the user experience, and the functionality of the interface should persist even when new features of added or (the dreaded) refactoring takes place on the codebase.

Writing UITest scripts prevents the repetition of pressing that button for every path through the App (yes, you need to check how the App is actually used).

If your code uses network services (and, it probably does) you will need to think about how you might mock or otherwise test the software without making real network calls.

Programatically creating UI tests can ensure that your users will be able to traverse and use your App when in production. This is likely a good thing, as your users define whether your App is successful or not.

Integration testing

One issue with Unit testing is that by definition these tests check isolated sections (perhaps individual classes) of code. However in software development the interaction between units and classes is also important (for example Design by contract pushes the interface between software to the foremost part of the software development process).

For example, are calls between classes made in the right order where there are dependencies involved?

To test these interfaces Integration testing comes to the rescue where real components and services are used (rather than mocked substitutes) are used to test the interaction. Now although I have said that real components and services are used, if you are testing the relationship between A and B you may mock the tangentially related object C, and during this testing we would expect all possible cases (edge and error cases) to be tested.

It is possible that bugs become apparent only when the integration is tested, and therefore the integration test can be an essential test becore any code is released into production.

End-to-End testing

End-to-End testing should test the entire function of the software. A common way of testing end-to end is to use scripted tests with user journeys written and tested against.

To run these End-to-End tests different devices would be needed to run the tests, however there are physical limits as to how many different device configurations can be run (and the installation and management of the infrastructure to do so can be rather large too).

As a result, it is possible to run UI automation in the cloud, in fact Amazon have a AWS Device Farm to help you run test scripts on a rather larger number of devices. These tests can happen in parallel (as the devices are simulators rather than real devices) so can be completed in a smaller amount of time. However there is a price attached, and since complex tests can take a longer amount of time to complete (and prices are based on device time) which may place perverse incentives onto the testing process. Be aware!

Bonus: Subsystem tests

There are bugs that Unit testing and Integration testing are not designed to find. An example of this is when an object of service A is decomposed into B and C and a requirement failed to be captured by the latter two — so we test at a higher level of abstraction to find such errors and bugs.


Testing is a really important part of the software development process. There are a great deal of tools out there to help you, in fact Amazon have the AWS Device Farm to help you test different mobile devices to prevent you from needing to own them all — and automate testing the same way that any software development task should be.

Any questions? You can get in touch with me HERE

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store