The Society Of The Spectacle

People lives have become a show, every happening, even the horrible ones are a spectacle to watch and enjoy with pop corns and a good dose of criticism. For example, the Depp-Heard trial right has…

Smartphone

独家优惠奖金 100% 高达 1 BTC + 180 免费旋转




Tips for TDD and unit tests

Posted on March 6, 2017

Test driven development is something so elementary for me I can’t imagine writing a code without at least some TDD. Learning TDD was very eye opening for me in many ways. One of the fundamental problems of TDD is its name — Test driven. That led developers focus on the testing side not on the code design side of the whole thing.

Unit testing to be exact. The problem is that tests are a guide to the goal not the goal itself. The goal is modular, clean and well designed code. TDD is of course not the ony way to get there. Experience is another. TDD is the way to get that experience.

If test should drive our code implementation we have to write our tests before our implementation. This is well known image which describe process of TDD.

You work in short iterations and repeat these steps over and over — Write a failing test. Make it pass quickly. Refactor the solution.

This is most important of all. Listen what test is telling you. If it is painful to write — the test is telling you that there must be different way how to write the code, better one. Such painful things might include: long setup code, lot of mocking, or you even have to use some workarounds to write the test.

See my other posts: Your mock is a joke and Signalling in programming

Looking at the tests is a first thing to do when looking at unknown code. It’s a living documentation what code can do and what contracts it has. Naming the tests helps tremendously. For example a calculator.

and now guess what the code does? Does add operation takes two arguments? Does it take negative values? The exception is thrown under which conditions? Lets fix it

This style of naming has other advantages as well. Naming is easy if you understand the problem you are solving. It’s also easy if the problem is small enough to capture in short sentence. If figuring the name for test is hard we should break the code under the test to smaller pieces.

Failed well-named test are also a very good hint where the problem is. Failed testCalculation vs variablesInInputStringAreReplacedByTheirValues

As you can tell from the example test names — there is no one-to-one relationship with test methods and production code methods. We are not testing methods, we are testing features of the code. Same applies for classes. One test per class is not a good pattern.

Apart from this it is so much more readable to have the result written as is in the assert part because you can quickly know what the code returns without reading some other lines. Consider this example

This test will fail either if our tax calculations or our vip status detection is not correct. Follow earlier tip for naming the tests it should be obvious even before writing the asserts. taxIsCalculatedAsPercentageAndVipStatusIsDetected does not sounds right to me. Split it in two tests. But do not follow the single assert rule strictly. Often it is completely ok to have more asserts, but they all have to verify single aspect of the feature. Be aware JUnit will fail at the first assert without executing the rest.

You might find yourself creating inputs unrelated to the output you are testing. That is exactly the kind of feedback test is giving you. The method probably does more than it should.

This is not TDD specific tip but I have to mention it. When testing code for exceptions throw custom exceptions from code. Otherwise it wont be testable.

Such generic exception might be thrown from the code you don’t have under control and the test will pass even if it should not.

You should run your tests very often. Long running tests results in doing something distractive instead. It also results in long running pipelines in your CI.

Every of your test should be able to run anytime, offline, without any additional setup. They should be executable in any order, in parallel, all at once or just single test. All inputs should be declared and test should have no side effects (setting any global state). This allows parallel execution and thus quick CI pipeline.

As I mentioned in the intro. Writing test-code-refactor way is an iterative process. When doing same things again and again it is important to get rid as much litter activities as possible. Learn your IDE shortcuts, learn how to execute tests with single command or a key press.

When writing the test don’t think about the finished solution. Write the test code as clean and descriptive as possible. Design object to copy your business not your technical solution. Do you handle money? Use Money object, not BigDecimal or anything else. It will represent your intentions better and will not tie you with single solution. The result will be modular and flexible code.

Or even better do not rely on side effects at all. Take input you need and produce output. Do not care where those inputs come from and how the output will be handled. Again this results in modular code.

Add a comment

Related posts:

Do you know Why Smart Phone Industries Wont Die.

When Smartphones came into the market we all had an impression it was priced high. Then it become affordable , Now 4G phones are available for even Rs 5000. If you think mass production is the only…

How to scale data fetching with SWR

Whenever I had built applications before, I limited myself to creating an effect that inserted data into the state of the single component. Later, after trying SWR, I realized that without this…

How to organize a massive number of distributed events

From American presidential candidates like Bernie Sanders to the global Youth Climate Strikes, the most exciting movements are scaling the capacity of their organizing by mobilizing supporters to…