Clean Code – A Testing Overview

Having recently completed Clean Code by Robert C Martin, I had initially planned on doing a book review. Having since seen how many book reviews have already been done I decided against it.

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.

 

F.I.R.S.T

Robert outlines five key rules to consider when writing tests:

FAST

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.

INDEPENDENT 

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.

REPEATABLE 

Tests should be repeatable against any environment. Tests should be able to run against QA and Dev environments and should also have the option to run locally on a developers machine. This normally involves parameterising your tests so URL’s and credentials can be passed into the tests. Look out for my post on adding parameters using Gradle.

SELF-VALIDATING

Your tests should have a boolean output, they should either pass or fail and should contain an assertion that returns the results. Without that, your test is essentially worthless. When designing your assertions be sure to also provide a valid output to help speed up the analysis. Bare in mind, your test failures are likely to be viewed by someone other than yourself.

TIMELY

This ordinarily refers to the development of unit tests as they would normally need to be completed before production code. In general, the sooner all levels of tests from unit to end-to-end are completed, the sooner the production code can be validated. The sooner things are validated, the cheaper it is to fix potential bugs
Please follow and like us:

Leave a Reply

Your email address will not be published.