Skip to content
Branch: master
Find file History
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Type Name Latest commit message Commit time
Failed to load latest commit information.


  • Prefer tests where all its 4 steps (setup/exercise/verfication/teardown) are clearly identifiable - This helps make tests easy to understand. [1] [2]

  • Avoid the use of let/let!/before - The use of these Rspec constructs over nested describe/context blocks tends to spread the multiple steps of testing over different blocks which makes what is happening in these steps harder to understand. [3]

  • Use Rspec contexts as a way to show that blocks of code are related - Avoid using context blocks as a way to remove incidental duplicaton between blocks. Use contexts so that their description shows how blocks of code are related. Contexts should be used as a way to group high level concepts together. This is a corollary of the guideline above. [18]

  • Don't test private methods - Private method tests create unnecessary coupling between the tests and the implementation details of an object and they break encapsulation. Testing private methods is an additional barrier to refactoring (because tests also have to be changed even if the object's API and behaviour is kept the same). Testing private methods is unnecessary because their behaviour is covered by public methods. [6] [5] [4]

  • Remember that the purpose of tests is to catch regressions, provide documentation, and reduce costs (i.e. time and money) and help with application design - When in doubt remember this. [1] [6]

  • Don't stub the system under test (SUT) - If an object is so complicated that there is a need to stub it in order to test it then that should be used as a guide to change the design. Also stubbing the sytem under test kind of violates the encapsulation of that object. [7] A reasonable exception to this are cases in which one cannot change the SUT (e.g. framework code, or legacy code) [8]

  • Remember that tests are a tradeoff of confidence, coverage and speed - The tradeoffs one does depend largely on the context. This impacts in which layer to test (i.e. unit, integration), what to test (e.g. sad path, happy path), which tools to use (e.g. database, mocks, real objects, fakes) [9] [1] [27] [28]

  • Only load ActiveRecord/Rails for tests that require it - loading Rails takes significant time when running tests. Fast tests are good. spec_helper, rails_helper and active_record_helper are your friends. [10] [11]

  • Prefer using, FactoryGirl.build_stubbed(:model),, FactoryGirl.create(:model) (in this order) - not all tests need persisted data. not all tests need to hit the database. tests that don't hit the database are faster. [13] [14]

  • Specify a single behaviour in each example - this constrasts with the common advice of using only one assertion per example in Rspec. Multiple expectations might imply a single behaviour. [15]

  • Always pass attributes to FactoryGirl which are relevant to the test - this gives needed information to the person reading the test regarding the causes on which it depends. Specifying everything in the factory leads to the same issues that fixtures have and FactoryGirl attempts to avoid. [16] [1]

  • What to test: Incoming messages should be tested for their return values; Outgoing messages that have side effects should be tested to ensure they get sent; Outgoing messages without side effects should not be tested. [17] [6]

  • In unit tests, units are not classes - A test is a unit if it runs fast and if it is easy to localize the source of test failures, therefore a unit might be a representation of multiple classes collaborating. [8] [19] [20]

  • Use tests as a way to define proper contracts and boundaries between components [21] [32] [33]

  • Use FactoryGirl's traits [29]

  • Prefer using Rspec for integration tests rather than Cucumber [30]

  • Prefer spies over mocks in Rspec [31]

  • Mock roles not types [33] [21]

  • Don't mock types you don't own [33] [21]

  • Keep controller tests simple [34]


You can’t perform that action at this time.