Ideas for testing anti-patterns. Just collecting ideas here and will possibly edit down for an article or talk later. Send suggestions to @jimweirich or email to jim.weirich@gmail.com. Thanks.
| Testing for exact class (should check behaviour, not implementation) | |
| Overmocking, leading to fantasy testing | |
| Huge setup method (via @paytonrules) | |
| God tests -- Testing everything end to end and specifying the behaviour along the way (via @kevinclark) | |
| Mocking the object under test -- essentially testing that you have have mocked (via @hgimenez) | |
| conjunction examples (should do this and this and this) - testing too many things at once (via @brentsnook) | |
| lots of code to setup the SUT. Use factories, fixtures, or moms. If SUT setup is hard then it's too hard to test and reason with (via @matthew) | |
| Testing an algorithm with an algorithm - eg. date calculations by, calculating dates (via @haruki_zaemon) | |
| mixed state and interaction based assertions in a single example (via @brentsnook) | |
| multiple assertions in a single example (via @brentsnook) | |
| Relying on state from a previous test as setup (via @haruki_zaemon) | |
| Assertions/expectations involving ephemeral values/quantities: eg real-time, precise elapsed-time, disk sizes, disk locations (via @haruki_zaemon) | |
| testing private methods: If you want to test them, make them public (perhaps as part of another class)(via @haruki_zaemon) | |
| stating interaction in example name rather than behaviour - "should call User finder" vs "should retrieve User by name" (via @brentsnook) | |
| tests that talk about more than one functional concept, tests with too much setup, nested mocks, too many mocks (via @dastels) | |
| 1-1 test-method or TestCase-Class correspondance (@via dastels) | |
| Failing to spec edge cases. Underspecification. (via @hgimenez) | |
| False description: test description falls out of sync with test example. (via @elight) | |
| Narrative tests. Setup and assert, then modify and assert, then modify some more and assert. | |
| Overmacroing -- leads to seemingly readable tests backed by so much code that the tests are no longer immediately comprehensible (via @elight) | |
| Using fixtures (via @elight) | |
| Refining @brentsnook's, s/interaction/implementation. Using implementation details in test name/description. (via @elight) | |
| Corrollary to @hgimenez (and to point out that anything other than path testing is "art"), "Testing too much: Overspecification" (via @elight) | |
| Testing private methods via send (via @bgswan) | |
| overly DRY tests that sacrifice comprehension and hence the documentation value (via @bmabey) | |
| Setting expectations that private methods get invoked, e.g. test_class.should_receive(:some_private_method) (via @bgswan) | |
| Implementation-Driven Testing. (Read: code first, test later). Symptoms include "hard to test", "too much setup", "hard to mock" (via @dbrady) | |
| Using wooly words like 'should' instead of "MUST", but maybe that's from a mis-spent youth reading RFCs. :) (via @mathie) | |
| Higher level abstraction for tests - Based on the notion that with anti-patterns, assertions and expectations become implicit. (via @bigdaddytee) | |
| Maybe this one's controversial: testing declarative has_many macro with an assert_has_many macro. Doesn't really test behavior. (via @usergenic) | |
| *not* mocking third party services (the classic "am I testing my own code or am I testing X -- where X is often Rails ;-) ) (via @elight) | |
| overmocked: a test that verifies the mocks it's created, rather than the code it's supposedly checking (via @cflipse) | |
| test-later specs that verify the bugs already present (via @cflipse) | |
| Restatement of overmacroing: OverDRYing tests at expense of readability. (via @elight) | |
| Testing the framework, not the code that uses it (via @mikewoodhouse) | |
| Saying your testing one thing, then testing another (via @paulanthonywils) | |
| Excessive meta-programming in the test code base. | |
| @model.predicate?.should be_true rather than @model.should be_predicate | |
| Expecting that a certain implementation is used (i.e., User.should_receive(:find_all_by_name).with(a_name)) which handicaps refactoring (User.find(:all, :conditions => { :name => a_name }) is logically the same). |