- By Patricia Bourrillon & María Dueñas
- ·
- Posted 20 May 2024
SaaS tools for improving productivity
Can using external tools help improve my team's productivity? This is a very common question among software development team leaders. The answer is a..
This post is a follow up on a series around TDD anti patterns. In the previous episode, we covered: the mockery, the inspector, the generous leftovers and the local hero, which are part of the 22 anti-patterns listed by James Carr.
In this blog post, we focus on four more of them, named: The nitpicker, The secret catcher, The dodger and The Loudmouth. Each one focuses on a specific aspect of code that makes testing harder. The four presented in this post are somehow connected to starters in TDD, most of them are patterns found by those who have not experienced writing applications guided by tests.
Besides that, according to the survey, we found that these are four of the least popular anti-patterns.
If you prefer to watch the workshop in which we talked about these anti-patterns, you can click on this link.
We continue our anti-patterns series of workshops with the next chapter coming on march 17th. Sign up here.
The survey previously revealed, the secret catcher is in the 7th position of the most popular tdd anti-patterns.
The secret catcher is an old friend of mine. I have seen it in different code bases, and often I compare this anti-pattern to the “hurry” in which features need to be released.
It’s called the ‘secret’, because you don't know that the code is supposed to throw an exception, instead of handling it (catch) the test case ignores it. The secret catcher is also related to The Greedy Catcher that hasn't been covered yet.
The following example written in vuejs with apollo client is an attempt to depict such a scenario, where the method seems to be fine and does what it is supposed to. In other words, it sends a mutation to the server to remove the payment type from the associated user and in the end it updates the user interfaceI to reflect that:
The javascript test is written using jest and the testing library, and here is a challenge for you, before going any further in the text, can you spot what is missing from the test case?
Let's start with the missing assertion at the end of the test case. If you haven't noticed, the last step that the test does is to wait for the click event, and that's it. For some feature that removes a payment method from a user, asserting that a message is shown would be a good idea.
Besides that, the test case relies on a specific setup that the graphql mutation will always work, in other words, if the graphql mutation throws an exception in the production code, but there is no sign of it being handled. In this scenario, the test case relies on jest to report the error, if any.
The survey previously revealed, the nitpicker is in the 8th position of the most popular tdd anti-patterns.
As the definition goes, the Nitpicker is noted in web applications where the need to assert the output is focused on an entire object rather than the specific property needed. This is common for JSON structures, as depicted in the first example.
The following code asserts that an application has been deleted. In this context, an application is a regular entry in the database with the label “application”. Note that this example in PHP is used to assert the exact output from the HTTP request, nothing more, nothing less.
In this sense, this test is fragile for a specific reason: if we add another property to the response, it will fail, complaining that the json has changed. For removing those properties, such failure would be helpful. On the other hand, adding a new property should not be the case.
The “fix” would be to replace the “exact” idea in this assertion to be less strict, such as the following:
The change here asserts that the desired fragment is indeed in the output, no matter if there are other properties in the output, as long as the desired one is there. This simple change opens up the door to move away from the fragile test we had in the first place.
Another way to not face the nitpicker is to look for the properties you want to. The following code is from an open source project that handles the s3 sining process to access a resource in amazon s3:
The code has three assertions to assert that it has the desired property instead of checking all at once regardless of the output.
Another example of how to approach such assertions is the code extracted from an open source project that aims to collect and process the four key metrics:
Once again, the RestAssured looks for property by property in the output instead of comparing everything in the output as depicted in the first example.
Testing frameworks usually offer such utility to help developers to test. For example, in the first example, Laravel uses the syntax assertJson/assertExactJson. The second example uses chai to depict how to assert specific properties in an object. Last but not least, RestAssured is the one used to depict how to deal with the nitpicker in the kotlin ecosystem.
The survey previously revealed, the dodger is in the 8th position of the most popular tdd anti-patterns.
The dodger, in my experience, is the most common anti-pattern when starting with testing first. Before diving into the code example, I would like to elaborate on why the dodger might appear.
Writing code in a TDD manner implies writing the test first for any code. The rule is: start with a failing test. Make it pass, and then refactor. As simple as it gets, there are some specific moments while practising this flow that the question “what should I test” kicks in.
As the rule goes, the common approach is to start writing tests by one class and one production class, meaning that it will have a 1-1 relationship, then, the following question is: “how small should be the step to write a test?”. As this “small” is context dependent, it’s not that clear to what is a minimum test code to move to the production code. Even though there are some videos and practitioners that make it a breeze.
Those two questions, while starting practising TDD are common, and they might lead to the dodge, as it focused on testing specific implementation code rather than the desired behaviour, to depict that take the following production code:
The goal here is to validate this Author object, to be created, the given array should hold valid data and if not, an exception will be thrown. Then, the next up is the testing code:
The first thing that I noted when skimming through the code is that if I need to change how I get the author name (rename the method) it is required to change the test code, even though the desired behaviour hasn't changed - the validation is still required.
Another approach would be to rewrite the single test case, by multiple test cases, catching the desired exception if an undesired value is passed, then encapsulating it in a validator class to prevent the coupling from the test and production code.
The survey previously revealed, the loudmouth is in the 8th position of the most popular tdd anti-patterns.
When developing, adding some traces to see if what the code is doing matches the developer's understanding is something common, we can call that debugging, often used when a developer needs to understand a piece of code.
TDD practitioners argue that once TDD is practised, no debugging tool is needed, be it a print statement or be it adding breakpoints into the code. Therefore, what happens if you don’t have that much experience with TDD?
Often the answer is a mix of both, debugging and using the tests to talk with you. For example, the following code depicts a test code that can handle an error if it happens to receive an invalid javascript code. Keep in mind that the code is used to parse javascript code and act upon its result:
The check is straightforward. It checks if the desired strategy wasn’t called as the code is an invalid javascript code and checks if the result was the boolean false. Let’s see now what the implementation of this test looks like:
Ideally, working in a TDD fashion, the console.log used would be mocked from the start. It would require verification of when it was called and with which message. This first hint already points to an approach that is not test first. The following image depicts what the loudmouth causes, even though the tests are green, there is a warning message - did the test pass? Did the change break something?
Steve Freeman and Nat Pryce give an idea why logging (such as this console.log) should be treated as a feature instead of a random log used for whatever reason.
The following snippet depicts a possible implementation mocking out the console.log and preventing the message to be displayed during test execution:
With the mocked console, now it’s possible to assert the usage of it instead of printing the output while running the tests, the version without the loudmouth would be the following:
In this post, we went through four more anti-patterns related to developers starting with TDD. Those covered are the least popular anti-patterns that came up in the survey, the secret catcher at 7th, the nitpicker, the dodge and the loudmouth at 8th.
We saw that the secret catcher is tricky, and it seems to be testing what it is supposed to test, but with close inspection we can spot the miss handling exception. The nitpicker on the other hand, points to fragile tests, in which the assertion used to test focuses on more things than it needs.
The dodge is the classic anti-pattern when starting with TDD. It leads to a relationship one-to-one between the test and the production code. Last but not least, the loudmouth can cause the developer to doubt if the test that is passing is green for the correct reason, as the output pollutes the output while the tests are being executed.
All in all, we reached a point in which we covered more than half of the 22 anti-patterns listed by James Carr; those four added to our toolkit more information while test driving applications.
Can using external tools help improve my team's productivity? This is a very common question among software development team leaders. The answer is a..
You have reached the highest level. You have completed the learning phases and we move on to the more complex katas. Remember that in the link of..
Our recommendation is that you first go through Object-Oriented Programming katas so that you can move on to more complex testing concepts. If so, we..
Join our newsletter for expert tips and inspirational case studies
Join our newsletter for expert tips and inspirational case studies