HTML and CSS Reference
Developers who are unfamiliar with unit testing often ask “how do you test your
tests?” The answer, of course, is that we don't. That does not imply that we do
not take measures to reduce defects in tests. The most important way to reduce the
chance of bugs in tests is to never implement logic in tests. A unit test should be a sim-
ple sequence of assignments and function calls followed by one or more assertions.
Apart from keeping tests stupid, the most important tool to catch erroneous
tests is to write and run them before implementing the passing code.
17.3.1 Run Tests before Passing Them
When tests are written before the required production code, they should also be
run before passing it. Doing so allows us to verify that the test fails for the expected
reasons, thus giving us a chance to catch errors in the test itself.
Failing a test with an articulated expectation as to how and why the test should
fail is in fact the most effective means with which we can fight buggy tests. Skipping
this point, we might move on to pass the test immediately. As soon as we have
started writing production code, we are a lot less likely to discover faulty testing
logic and might as well end up passing the test, thus sneaking the wrong behavior
into production code without having tests that can tell us as much.
17.3.2 Write Tests First
To be able to run tests before passing them we obviously need to write them first
as well. Because this topic has given some insight into the test-driven development
should not come as a surprise.
Writing tests upfront has benefits beyond making it easier to catch faulty tests.
Tests first ensure that code is inherently testable. If you have ever attempted to
retrofit unit tests onto code that was not originally written with testability in mind,
you will appreciate the importance of testable code.
Writing testable code is not useful only to test it. Unit tests are secluded sample
uses of production code, and if writing a test for any given behavior is hard, well,
then using that particular behavior is hard. If using a small part of the code base
requires half an application's worth of setup, then the design might not be optimal.
For example, requiring a DOM element and its CSS API in order to transition a
color from red to green is a good example of code that is hard to use for the same
reasons as why it is hard to test.