3 Types Of Unit Tests That Everyone Should Know

Jakub Sobolewski
3 min readOct 18, 2023

--

When approaching to write a unit test, we might ask ourselves:

  • What should I test?
  • How should I test?
  • And even when should I test?

Getting answers to these questions helps overcome writer’s block.

To make it easier to think about what to test and to make a more informed decision on how we need to test it, we may categorize tests into:

  • Direct Response Tests.
  • State Change Tests.
  • Interaction Tests.

Let’s see in what circumstances should each type be used.

Direct Response Tests

  • They check whether a return value or an exception matches the expectation.
  • These tests ensure that the core functionality of the code works correctly.
Direct response test.

Tips

  • Don’t test a lot of different values if the new combination doesn’t test new behavior. E.g., testing mean(1:10) and then mean(1:100) doesn’t improve our confidence that mean function works as expected.
  • Use assertions to convey intent. E.g., if you don’t care about the order of a vector, consider using testthat::expect_setequal instead of testthat::expect_equal to only assert on its content.
  • Don’t duplicate assertions. E.g., if you already use testthat::expect_equal on a vector, does adding an assertion on its length with testthat::expect_length add more safety?

State Change Tests

  • These tests help validate the impact of certain actions on the system’s state.
  • They confirm that the behavior results in the expected changes, such as modifying a list and confirming its size change.
State change test.

Tips

  • Don’t share state between tests. It may make tests more fragile and more difficult to understand.
  • Avoid iteration. Don’t check if Stack can handle 0, 1, 2, 3, 4, …, calls to push. Use chicken counting: zero, one, or many.

Interaction Tests

  • These tests ensure proper communication and integration between different parts of the system.
Interaction test.
  • These tests examine how code interacts with external components, often simulating dependencies or external services. Mocks, Fakes, Stubs and Dummies are used to control these interactions and validate that the code interacts correctly with external entities.

Tips

  • Complex mock will make tests brittle and difficult to understand. They typically need to be created when interactions in the code are complex or not defined well enough.
  • Notice how much setup is needed to run a test. Use this feedback to improve and simplify production code. Code that is easy to test is easier to maintain.

--

--

Jakub Sobolewski

I help R developers get better at testing | Tech Lead @ Appsilon