Solvro Talks - Unit Tests
What are Unit Tests?
Unit tests are a software testing technique where the smallest, isolated segments of code (called units) are checked for correct operation. Units can be methods, classes, modules, or packages. Key characteristics of unit tests are automation and repeatability, meaning they can be run multiple times without changing the results, and speed - they provide immediate feedback on the code operation.
Benefits of Unit Tests
Unit tests offer a range of benefits:
● Easier code management: Code that is unit tested is usually easier to maintain and modify.
● Fewer errors: Regular testing reduces the number of errors in the code during its development.
● Protection from recurring errors: Tests help detect and eliminate small, recurring errors that may affect system stability.
What Does a Unit Test Look Like?
A good unit test should:
● Have an appropriate name, such as shouldReturnListOfEvenNumbers or shouldReturnListOfUniqueNumbers.
● Comply with the given/when/then convention, which aids in writing structured tests.
● Be independent of other tests.
● Have an appropriate test class name with the suffix Test and be placed in the correct package.
What Should We Test?
Unit tests should cover:
● Conditional statements: Such as if/else and switch.
● Logical expressions: Logical operations used in the code.
● Ternary operators: For example, variable ? "true" : "false".
We do not test:
● Private methods: Unit tests are exclusively for public methods.
● Getters and setters: Because they are usually trivial and testing them does not add value.
Example of a Unit Test:
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.assertFalse;
import org.junit.jupiter.api.Test;public class NumberUtilsTest {
@Test
public void shouldReturnTrueWhenNumberIsEven() {
// given
int number = 4;// when
boolean result = NumberUtils.isEven(number);// then
assertTrue(result);
}@Test
public void shouldReturnFalseWhenNumberIsOdd() {
// given
int number = 5;// when
boolean result = NumberUtils.isEven(number);// then
assertFalse(result);
}
}
class NumberUtils {
public static boolean isEven(int number) {
return number % 2 == 0;
}
}
Techniques for Writing Unit Tests
There are two main techniques for writing unit tests:
● Code first: A traditional approach where we write the code first and then the tests. Often used in integration tests.
● TDD (Test Driven Development): We write a test first, then the code that should pass that test, and then refactor the code. This process occurs in the cycle RED -> GREEN -> REFACTOR.
Mocking and Its Significance
Mocking is a technique that involves replacing the actual objects being tested with their empty implementations (mocks). It allows for:
● Recording interactions: All interactions with the mock are recorded for later verification.
● Checking return values: The ability to set what a method should return in a test. The Mockito library in Java is a popular tool for creating mocks and facilitates verification of interactions between objects.
Where to Avoid Unit Tests?
Some projects do not require unit tests, for example:
● Prototypes: Projects with a short lifespan that do not require intensive testing.
● Game Development: Games often require more complex integration and manual tests.
● UI/UX: User interface tests are typically not suitable for unit tests.
Summary
Unit tests help maintain high code quality and minimize the number of errors. At this level, programmers should not neglect unit testing! It is an integral technique that we should apply.