The importance of design for TDD

Stop me if this sounds familiar. You've read multiple articles about the importance of TDD (test driven development) and unit tests. You understand the basics of unit tests and frameworks for mocking up data and examples. Maybe you've created unit tests that helped you in refactoring, or finding issues in the service methods, so you understand the value of good unit tests. But you can't help feeling like you're missing something in how you're doing TDD. Your unit tests are so simple they feel useless, like a test that mocks some data for a repo and then verifies that it got the mocked data. Or maybe you don't even know what unit tests to create, so you start in on your implementation and add unit tests after the fact to cover your code.

What's missing? It's possible you aren't doing enough design work to fully understand the problem you're trying solve, and without understanding the problem you can't effectively test the problem. Once you understand the problem, it becomes much easier to see where and how the proposed solution can go wrong, where it can fail, and what conditions are needed for success.

For example, let's look at this state diagram for a function/method to ingest some data, apply some modifiers, and save the data to storage.


Let's walk through the unit tests we need, based on this diagram.
  • Send some invalid data and make sure the error gets logged and returned.
  • Send valid data, but handle not finding data modifiers for that data.
  • Send valid data and find modifiers, but handle any errors applying the modifiers.
  • Send valid data and find modifiers, and verify that the modifiers are applied correctly.
  • Send valid data, find and apply modifiers, and handle any errors while saving to storage.
  • Send valid data, find and apply modifiers, and save to storage (happy path).
It's possible that at this point we don't even know how the methods will be implemented and are unable to fully create the unit tests. That's totally OK, because even just stubbing out the unit test methods with inconclusive asserts is an improvement over trying to backfill unit tests after implementation. As we start writing code, we are now writing with our tests in the back of our mind, and we'll be more effective in handling edge cases and errors. And all of this, from design to TDD to better coding, makes us better developers.

Comments

Popular posts from this blog

Adding Font Awesome to .NET MAUI App

Comparing SELECT Performance of Joining Integers vs GUIDs in SQL Server

Performance: SQL Server vs MongoDB (JSON data)