Testing is a critical piece of good software. They are extremely useful for catching bugs early in the development process which can save your organization time and resources. There are a lot of types of testing, and the two main ones used by software developers are unit and integration tests.
It’s not always clear what each one of these tests is used to do. In this article, we’ll discuss what each type of test does and compare and contrast them.
What are unit tests?
Unit tests evaluate the smallest pieces of code in a system. In order to test the code, unit tests run a function with some input and check the output. They typically don’t interact with any other systems and are self-contained.
Because unit tests are running on a small piece of the system, they usually encompass one or a few functions at most. This helps them to run extremely quickly, on the order of milliseconds.
Let’s take a look at an example. We can create a python
calculator with two functions: add
and subtract
.
class Calculator:
def add(x, y):
return x + y
def subtract(x, y):
return x - y
and a unit test file
def test_add():
assert Calculator.add(1, 2) == 3.0
assert Calculator.add(1.0, 2.0) == 3.0
def test_subtract():
assert Calculator.subtract(1, 2) == -1.0
assert Calculator.subtract(2, 1) == 1.0
Note the two functions in the test file: test_add
and test_subtract
. These two tests represent unit tests as they are each running a simple function that will return quickly.
Unit tests are useful because they are often written at the beginning of the development process. That means that they can be used to catch bugs early on which helps prevent easy bugs from popping up later. Since they don’t interact with any other systems, they are not greatly affected by code changes. This helps to add resiliency to your codebase and prevent breakages from happening downstream.
What are integration tests?
Integration tests are a step above unit tests. They combine different functions and test how they interact together. Assuming that a piece of code is well unit-tested, an integration test doesn’t need to ensure that each function returns the right output. Instead, they are more focused on ensuring that the output of a function is a valid and useful input into another.
Because integration tests encompass multiple functions up to a few classes or modules, they can be far more complex. This means that they will often take longer to run than unit tests. But also since they are not just testing that functions behave properly, they may need to access other dependencies and resources. For example, an integration test may check that a database entry has been properly changed or that a cache has the proper elements in it.
Integration tests are valuable in determining if a code flow works as expected. They may test for the idempotency of a code path or that different layers of an API work together. This gives developers confidence that their code will run successfully.
In our calculator example, let’s say that we have some code to display the result. An integration test might check that a divide by 0 is handled properly by the controller and view logic.
Comparing unit and integration tests
As you can see, both types of tests are incredibly important in software development. Let’s take a look at their differences:
Unit Tests | Integration Tests | |
Scope | Single to a few functions | Few functions to multiple modules |
Speed | Fastest (in milliseconds) | Fast (in seconds) |
Dependencies/Resources | None | Possible |
Parallelization | Possible | Not recommended |
Used in TDD? | Yes | No |
Which type of test should you use?
So, which type of tests should you be using in your codebase? The answer is simple, use both types of testing.
If you don’t have the time or a company culture around writing that many tests, we recommend using integration tests. They are less likely to need to change and can decrease the testing burden. If you are a fast-moving startup, your code is expected to change frequently. Having integration tests over unit tests helps you to keep up with large-scale architecture changes as opposed to having to re-write large swaths of tests.
How does Codecov work with these types of tests?
As mentioned, testing code is critical. Knowing which parts of your codebase have not been tested will help you to ensure better code reliability and stability. Using a code coverage tool to generate reports will help you uncover what lines of code aren’t been tested in your test suites.
The great thing about using Codecov is that it ingests coverage reports from both types of tests. There’s no other steps needed, Codecov automatically merges coverage reports together seamlessly into one.