Author: Haroon Khalil

  • Test smells

    In the previous sections, we discussed some best practices for writing good test code. Now let’s discuss test smells. The term code smell indicates symptoms that may indicate deeper problems in the system’s source code. Some well-known examples are Long Method, Long Class, and God Class. Several research papers show that code smells hinder the comprehensibility and maintainability of software systems (such as the…

  • Tests should be easy to change and evolve

    Although we like to think that we always design stable classes with single responsibilities that are closed for modification but open for extension (see Martin [2014] for more about the Open Closed Principle), in practice, that does not always happen. Your production code will change, and that will force your tests to change as well.…

  • Tests should be easy to read

    I touched on this point when I said that tests should have a clear reason to fail. I will reinforce it now. Your test code base will grow significantly. But you probably will not read it until there is a bug or you add another test to the suite. It is well known that developers…

  • Tests should be easy to write

    There should be no friction when it comes to writing tests. If it is hard to do so (perhaps writing an integration test requires you to set up the database, create complex objects one by one, and so on), it is too easy for you to give up and not do it. Writing unit tests…

  • Tests should have a single and clear reason to fail

    We love tests that fail. They indicate problems in our code, usually long before the code is deployed. But the test failure is the first step toward understanding and fixing the bug. Your test code should help you understand what caused the bug. There are many ways you can do that. If your test follows…

  • Tests should break if the behavior changes

    Tests let you know that you broke the expected behavior. If you break the behavior and the test suite is still green, something is wrong with your tests. That may happen because of weak assertions (which we have discussed) or because the method is covered but not tested (this happens, as discussed). Also recall that…

  • Tests should have strong assertions

    Tests exist to assert that the exercised code behaved as expected. Writing good assertions is therefore key to a good test. An extreme example of a test with bad assertions is one with no assertions. This seems strange, but believe it or not, it happens—not because we do not know what we are doing, but because writing…

  • Tests should be repeatable and not flaky

    A repeatable test gives the same result no matter how many times it is executed. Developers lose their trust in tests that present flaky behavior (sometimes pass and sometimes fail, without any changes in the system or test code). Flaky tests hurt the productivity of software development teams. It is hard to know whether a flaky test…

  • Tests should have a reason to exist

    You want tests that either help you find bugs or help you document behavior. You do not want tests that, for example, increase code coverage. If a test does not have a good reason to exist, it should not exist. Remember that you must maintain all your tests. The perfect test suite is one that can detect…

  • Tests should be cohesive, independent, and isolated

    Tests should be as cohesive, independent, and isolated as possible. Ideally, a single test method should test a single functionality or behavior of the system. Fat tests (or, as the test smells community calls them, eager tests) exercise multiple functionalities and are often complex in terms of implementation. Complex test code reduces our ability to understand what is being…