Authors: Robert C. Martin, Dean Wampler| Published: 2008 | Pages: 2464| Amazon Link
In this series of posts, I will be extracting and summarising certain sections of the book that resonated the most with me.
Being a testing blog I thought it best to start with the subject of testing. Thankfully Robert dedicated a whole chapter to testing.
In chapter 9, Robert discusses the concept of unit testing in relation to clean code. Although as test developers our focus can sometimes be more concentrated on integration and end-to-end tests, I found I was able to appreciate a number of key concepts outlined in this chapter.
Keeping Tests Clean?
Robert states that having dirty tests is equivalent to if not wore than having no tests. Tests by their nature must evolve as changes to the production code are made. The dirtier the tests, the harder they are to change. The more tangled the test code, the more likely you are to spend time cramming new tests into an already messy test suite, which will in-turn take time away from writing new production code. As you modify the production code, old tests start to fail, and the mess in the test code makes it hard to get those tests to pass again. So the tests become viewed as an ever-increasing liability
The moral of the story is simple: Test code is just as important as production code. It is not a second-class citizen. It requires thought, design, and care. It must be kept as clean as production code.
Good Tests Allow Production Code To Improve
If we don’t keep our tests clean, we quickly lose the ability to rely on them. And without them, you lose the key component that allows your production code to remain flexible. Having a good set of tests gives developers the confidence to make changes without causing a failure. Without a good set of tests, from unit tests all the way to end-to-end tests, every change is a potential bug.
A good set of tests will alleviate that fear and allow your developers to improve the architecture and design of your application, your tests become the enabler of change
If your tests are dirty, then your ability to change your code is hampered, and you begin to lose the ability to improve the structure of that code. The dirtier your tests, the dirtier your code becomes. Eventually, you lose the tests, and the code rots.
What Makes A Clean Test
Robert outlines 3 key areas, Readability, Readability and finally… Readability.
Readability is perhaps even more important in automated tests than in production code. The journey of what is being tested should be clear to see, to the point that it can be used as documentation to prove a product’s functionality. What makes tests readable? The same thing that makes all code readable, clarity, simplicity, and denseness of expression.
A technique I often use when writing tests it to wrap more complex logic or test steps into their own methods, that in turn allow the actual tests to seem smaller and easier to understand, whilst also providing reusable steps
Each test should only cover a single test concept, this doesn’t necessarily mean a test can only have a single assertion, but the overall concept should remain constant.
Tests should be fast. Tests that run fast, fail fast, speeding up the feedback loop. When testing against the browser you can only go as fast as selenium allows but I’ve found that replacing browser calls with rest calls can dramatically speed up test runs. The key consideration to bear in mind is what the aim of the test is. Not every end-to-end test requires the browser for every step. Using parallelisation can also help reduce the time an overall test suit takes to run, which can help alleviate the issue of having longer tests.
Tests should not depend on each other. Any set up required for tests should be specified within a setup method, and this would normally be a set of general ‘set up’ task that are likely to be used against multiple tests. You should be able to run each test independently and in any order.
A key aspect to keeping test truly independent is to have data available that relates only to that test. This normally involves generating relevant data such as test users as part of the setup, whilst also removing this test data as part of the teardown.