1  Anatomy of a test

A good test makes it clear what it’s checking.

When a test mixes setup, running the system, and checking results, it gets confusing. Separating these steps into clear phases helps make the test’s purpose obvious. This way, anyone reading the test can follow along easily.

We can make this separation explicit with Arrange, Act, Assert comments.

Those comments aren’t just for show. They help you structure your tests and keep them focused. They also make it easier to spot missing steps or unnecessary complexity. They keep your tests consistent, which makes them easier to read and maintain.

If you are starting to write a test, put those comments in place first, then fill in the blanks.

1.1 Arrange

The first part of each test should setup the environment for the tested code.

test_that("...", {
  # Arrange 
  machine <- deep_thought$connect() 
  question <- "What is the answer to life, the universe, and everything?" 

  # Act

  # Assert

})

1.2 Act

The second part of each test is to call the code that’s being tested.

test_that("...", {
  # Arrange
  machine <- deep_thought$connect()
  question <- "What is the answer to life, the universe, and everything?"

  # Act 
  result <- ask_question(machine, question) 

  # Assert

})

1.3 Assert

The third part of each test is to assert that the code behaves as expected.

test_that("...", {
  # Arrange
  machine <- deep_thought$connect()
  question <- "What is the answer to life, the universe, and everything?"

  # Act
  result <- ask_question(machine, question)

  # Assert 
  expect_equal(result, 42) 
})

1.4 Teardown if needed

If we need to free resources, we should do that at the end of the test.

test_that(" ", {
  # Arrange
  machine <- deep_thought$connect()
  question <- "What is the answer to life, the universe, and everything?"

  # Act
  result <- ask_question(machine, question)

  # Assert
  expect_equal(result, 42)

  machine$disconnect() 
})