Guideline №2.) Avoid if-statements in a test
An if-statement in a test means the test is designed to do different things, depending on the situation. If’s need testing. How will you test the test? And will you test the test that tests the test? Where does it end?
From a requirements perspective, something either works or doesn’t. That’s static. The outcome of a test becomes less trustworthy if the test is dynamic, and tests become dynamic when they do things differently, depending on a situation.
Guideline №3.) Unit tests only “new()” the unit under test.
Unit tests are small. The test scope of a unit test is limited to just one single method or class. From that perspective it would make sense to only use the “new ()” keyword to instantiate the class that contains the method you’re testing.
Combining different classes, running different input through them and asserting the outcome, makes the test less targeted. Which class needs fixing when the test fails? Example:
Avoid these! Which class needs fixing when the test fails? Calendar or Schedule?
Don’t instantiate the dependencies of the class you’re testing, using the “new ()” keyword. Use frameworks like Moq or NSubstitute to create mocks and stubs to replace them. That makes tests more targeted and they’ll provide better feedback, that way:
Only instantiate the unit under test (Calendar) in your unit test. The bug must be in the Calendar class.
Guideline №4.) Unit tests do not contain hard-coded values unless they have a specific meaning
Unit tests are supposed to be descriptive: Given some input, when the code is being executed, then the result must be something.
Don’t hard-code test-data. That makes it harder to understand the test. Assume the following test fails, would you know what the problem is? You’ll have to debug to figure out what’s wrong:
Avoid these: It’s hard to figure out what’s wrong when such a test fails.
When fixtures are being generated with a framework, the test becomes a lot clearer. When the following test fails, it indicates that some code regarding the validation of a phone number has changed. You won’t have to debug to figure it out:
Only define the properties that trigger the logic you’re testing. In this case,
it should be obvious that something regarding the validation of a
phone number has broken when this test fails.
Guideline №5.) Unit tests are stateless
Nothing is worse than passing tests, and a broken application in production. Stateful tests can cause false positives. Assume the following example:
Avoid these: Stateful unit tests make the outcome of the test debatable.
Assume the GivenAppointment_ThenErrorOccurs executes first, then the GivenAppointmentThenAppointmentAppearsInList test creates either a false positive or a false negative.
Design unit tests to be trustworthy. Design them to pass regardless of their execution order. The outcome of tests must be the same no matter how often they’re being executed.