<PutYourCoverAltHere>

Unit Testing Principles, Practices, and Patterns: Takeaways

This book won’t teach you how to write a unit test step by step. But, it will teach you how unit testing fits the larger picture of a software project. Also, this book shows how to write integration tests and test the database. These are my takeaways.

1. What is a unit test?

“The goal of unit testing is to enable sustainable growth of the software project.” “It’s easy to fall into the trap of writing unit tests for the sake of unit testing without a clear picture of whether it helps the project.”

A successful test suite has the following properties:

A unit test is an automated test with three attributes:

  1. It verifies a small portion of behavior (a unit),
  2. does it quickly, and,
  3. in isolation from other tests

There are two groups of developers with different views about “isolation”: the London school and the Classical school.

For the London school, isolation means writing separate tests for separate classes. If a class has collaborators, we should test it using test doubles for every collaborator.

On the other hand, for the Classical school, it’s not the code that needs to be tested in isolation, but the tests. They should run in isolation from each other. It’s ok to test more than one class at a time if the tests don’t affect others by sharing state.

“A test—whether a unit test or an integration test—should be a simple sequence of steps with no branching”

A good unit test has these four attributes:

  1. Protection against regressions: “Code that represents complex business logic is more important than boilerplate code.”
  2. Resistance to refactoring: “The more the test is coupled to the implementation details of the system under test (SUT), the more false alarms it generates.”
  3. Fast feedback: “The faster the tests, the more of them you can have in the suite and the more often you can run them.”
  4. Maintainability: “How hard is to read a test” and “how hard is to run a test.”
Car cashed into a wall
That's a failing test. Photo by Gareth Harrison on Unsplash

2. What code to test?

Not all code is created equal and worth the same.

Types of Code based on complexity and number of dependencies
Types of Code by Complexity and Number of Dependencies

There are four types of code:

  1. Domain logic and algorithms: Complex code by nature
  2. Trivial code: Constructors without parameters and one-line properties
  3. Controllers: Code with no business logic that coordinates other pieces
  4. Overcomplicated code: Complex code with too many dependencies

Write unit tests for your domain model and algorithms. It gives you the best return for your efforts. Don’t test trivial code. Those tests have a close-to-zero value.

“Your goal is a test suite where each test adds significant value to the project. Refactor or get rid of all other tests. Don’t allow them to inflate the size of your test suite”

3. What is an integration test? And how to test the database?

An integration test is any test that is not a unit test. In the sense of verifying a single behavior, doing it quickly and in isolation from other tests.

Write integration tests to cover the longest happy path and use the same code that the “controllers” use.

Before writing integration tests for the database:

When writing integration tests for the database:

Voilà! These are my takeaways. Although this book has “Unit Testing” in its title, I really liked it covers integration tests, especially testing the database and data-access layer. I’d say this isn’t a book for beginners. You would take more out of this book if you read The Art Of Unit Testing first.

If you want to read more about unit testing, check my Unit Testing 101 series where I cover from what unit testing is to unit testing best practices.

Ready to upgrade your unit testing skills? Check my course Mastering C# Unit Testing with Real-world Examples on my Gumroad page. Practice with hands-on exercises and learn best practices by refactoring real-world unit tests.

Happy testing!