Clean Code Cheat Sheet Page 3

ADVERTISEMENT

Kinds of Automated Tests
Faking (Stubs, Fakes, Spies, Mocks …)
Test Not Belonging in Host Test Fixture
Red Bar Patterns
ATDD – Acceptance Test Driven Development
+
Isolation from environment
+
A test that tests a completely different testee than all other tests in the
One Step Test
+
fixture.
Specify a feature first with a test, then implement.
Use fakes to simulate all dependencies of the testee.
Pick a test you are confident you can implement and which maximises
Obsolete Test
learning effect (e.g. impact on design).
TDD – Test Driven Development
+
Faking Framework
+
A test that checks something no longer required in the system. May even
Partial Test
+
Red – green – refactor. Test a little – code a little.
Use a dynamic fake framework for fakes that show different behaviour in
prevent clean-up of production code because it is still referenced.
different test scenarios (little behaviour reuse).
Write a test that does not fully check the required behaviour, but brings you
DDT – Defect Driven Testing
+
Hidden Test Functionality
a step closer to it. Then use Extend Test below.
Manually Written Fakes
+
Write a unit test that reproduces the defect – Fix code – Test will succeed –
Test functionality hidden in either the SetUp method, base class or helper
Extend Test
+
Defect will never return.
Use manually written fakes when they can be used in several tests and they
class. The test should be clear by looking at the test method only – no
have only little changed behaviour in these scenarios (behaviour reuse).
Extend an existing test to better match real-world scenarios.
POUTing – Plain Old Unit Testing
+
initialisation or asserts somewhere else.
Mixing Stubbing and Expectation Declaration
Another Test
+
Aka test after. Write unit tests to check existing code. You cannot and
Bloated Construction
probably do not want to test drive everything. Use POUT to increase sanity.
Make sure that you follow the AAA (arrange, act, assert) syntax when using
If you think of new tests, then write them on the TO DO list and don’t lose
The construction of dependencies and arguments used in calls to testee
Use to add additional tests after TDDing (e.g. boundary cases).
focus on current test.
mocks. Don’t mix setting up stubs (so that the testee can run) with
makes test hardly readable. Extract to helper methods that can be reused.
expectations (on what the testee should do) in the same code block.
Learning Test
+
Design for Testability
Unclear Fail Reason
Checking Fakes instead of Testee
Write tests against external components to make sure they behave as
Constructor – Simplicity
+
Split test or use assertion messages.
Tests that do not check the testee but values returned by fakes. Normally
expected.
Objects have to be easily creatable. Otherwise, easy and fast testing is not
due to excessive fake usage.
Conditional Test Logic
possible.
Green Bar Patterns
Excessive Fake Usage
Tests should not have any conditional test logic because it’s hard to read.
Constructor – Lifetime
+
Fake It (‘Til You Make It)
+
If your test needs a lot of mocks or mock setup, then consider splitting the
Test Logic in Production Code
Return a constant to get first test running. Refactor later.
Pass dependencies and configuration/parameters into the constructor that
testee into several classes or provide an additional abstraction between
Tests depend on special logic in production code.
have a lifetime equal to or longer than the created object. For other values
your testee and its dependencies.
Triangulate – Drive Abstraction
+
use methods or properties.
Erratic Test
Write test with at least two sets of sample data. Abstract implementation
Unit Test Principles
Sometimes passes, sometimes fails due to left overs or environment.
Abstraction Layers at System Boundary
+
on these.
Fast
+
Use abstraction layers at system boundaries (database, file system, web
TDD Principles
Obvious Implementation
+
services, COM interfaces ...) that simplify unit testing by enabling the usage
Unit tests have to be fast in order to be executed often. Fast means much
A Test Checks One Feature
+
If the implementation is obvious then just implement it and see if test runs.
of mocks.
smaller than seconds.
If not, then step back and just get test running and refactor then.
A test checks exactly one feature of the testee. That means that it tests all
Isolated
+
Structure
things included in this feature but not more. This includes probably more
One to Many – Drive Collection Operations
+
Clear where the failure happened. No dependency between tests (random
Arrange – Act – Assert
+
than one call to the testee. This way, the tests serve as samples and
First, implement operation for a single element. Then, step to several
order).
documentation of the usage of the testee.
Structure the tests always by AAA. Never mix these three blocks.
elements.
Repeatable
+
Tiny Steps
+
Test Assemblies (.Net)
+
Acceptance Test Driven Development
No assumed initial state, nothing left behind, no dependency on external
Make tiny little steps. Add only a little code in test before writing the
Create a test assembly for each production assembly and name it as the
Use Acceptance Tests to Drive Your TDD tests
+
services that might be unavailable (databases, file system …).
required production code. Then repeat. Add only one Assert per step.
production assembly + “.Test”.
Acceptance tests check for the required functionality. Let them guide your
Self-Validating
+
Keep Tests Simple
+
Test Namespace
+
TDD.
No manual test interpretation or intervention. Red or green!
Whenever a test gets complicated, check whether you can split the testee
Put the tests in the same namespace as their associated testee.
User Feature Test
+
Timely
+
into several classes (Single Responsibility Principle)
Unit Test Methods Show Whole Truth
+
An acceptance test is a test for a complete user feature from top to bottom
Tests are written at the right time (TDD, DDT, POUTing)
Prefer State Verification to Behaviour Verification
+
Unit test methods show all parts needed for the test. Do not use SetUp
that provides business value.
Use behaviour verification only if there is no state to verify.
method or base classes to perform actions on testee or dependencies.
Unit Test Smells
Automated ATDD
+
Test Domain Specific Language
+
SetUp / TearDown for Infrastructure Only
+
Test Not Testing Anything
Use automated Acceptance Test Driven Development for regression testing
Use test DSLs to simplify reading tests: helper methods, classes.
Use the SetUp / TearDown methods only for infrastructure that your unit
Passing test that at first sight appears valid but does not test the testee.
and executable specifications.
test needs. Do not use it for anything that is under test.
TDD Process Smells
Test Needing Excessive Setup
Component Acceptance Tests
+
Test Method Naming
+
Using Code Coverage as a Goal
A test that needs dozens of lines of code to set up its environment. This
Write acceptance tests for individual components or subsystems so that
Names reflect what is tested, e.g. FeatureWhenScenarioThenBehaviour.
noise makes it difficult to see what is really tested.
these parts can be combined freely without losing test coverage.
Use code coverage to find missing tests but don’t use it as a driving tool.
Single Scenario per Test
+
Too Large Test / Assertions for Multiple Scenarios
Otherwise, the result could be tests that increase code coverage but not
Simulate System Boundaries
+
certainty.
One test checks one scenario only.
A valid test that is, however, too large. Reasons can be that this test checks
Simulate system boundaries like the user interface, databases, file system
for more than one feature or the testee does more than one thing (violation
No Green Bar in the last ~10 Minutes
and external services to speed up your acceptance tests and to be able to
Resource Files
+
of Single Responsibility Principle).
check exceptional cases (e.g. a full hard disk). Use system tests to check the
Make small steps to get feedback as fast and frequent as possible.
Test and resource are together: FooTest.cs, FooTest.resx
boundaries.
Checking Internals
Not Running Test Before Writing Production Code
Naming
Acceptance Test Spree
A test that accesses internals (private/protected members) of the testee
Only if the test fails, then new code is required. Additionally, if the test,
Naming SUT Test Variables
+
directly (Reflection). This is a refactoring killer.
Do not write acceptance tests for every possibility. Write acceptance tests
surprisingly, does not, fail then make sure the test is correct.
only for real scenarios. The exceptional and theoretical cases can be
Give the variable holding the System Under Test always the same name (e.g.
Test Only Running on Developer’s Machine
Not Spending Enough Time on Refactoring
covered more easily with unit tests.
testee or sut). Clearly identifies the SUT, robust against refactoring.
A test that is dependent on the development environment and fails
Refactoring is an investment in the future. Readability, changeability and
Naming Result Values
+
elsewhere. Use continuous integration to catch them as soon as possible.
extensibility will pay back.
Give the variable holding the result of the tested method always the same
Test Checking More than Necessary
Skipping Something Too Easy to Test
name (e.g. result).
A test that checks more than it is dedicated to. The test fails whenever
Don’t assume, check it. If it is easy, then the test is even easier.
Anonymous Variables
+
something changes that it checks unnecessarily. Especially probable when
Skipping Something Too Hard to Test
fakes are involved or checking for item order in unordered collections.
Always use the same name for variables holding uninteresting arguments to
Make it simpler, otherwise bugs will hide in there and maintainability will
tested methods (e.g. anonymousText).
Irrelevant Information
suffer.
Test contains information that is not relevant to understand it.
Don’t Assume
Organising Tests around Methods, Not Behaviour
Chatty Test
Understand the Algorithm
+
These tests are brittle and refactoring killers. Test complete “mini” use
A test that fills the console with text – probably used once to manually
Just working is not enough, make sure you understand why it works.
cases in a way which reflects how the feature will be used in the real world.
check for something.
Do not test setters and getters in isolation, test the scenario they are used
Incorrect Behaviour at Boundaries
Test Swallowing Exceptions
in.
Always unit test boundaries. Do not assume behaviour.
A test that catches exceptions and lets the test pass.

ADVERTISEMENT

00 votes

Related Articles

Related forms

Related Categories

Parent category: Education
Go
Page of 4