Close
Glad You're Ready. Let's Get Started!

Let us know how we can contact you.

Thank you!

We'll respond shortly.

LABS
Railsconf: Don't mock yourself out – Dave Chelimsky

Martin Fowler says Mocks Aren’t Stubs and talks about Classical and Mockist Teting. Dave shows slightly amusing set of photos about “ists” – Rubyists etc. Ist bin ein red herring. The big issue here is when to use a mock.

Overview of Stubs and Mocks

Terminology: test double – an object standing in for a real object (like a stunt double).

customer = Object.new
logger = Object.new
customer.stub(:name).and_return('Joe Customer')
logger.should_receive(:log)

customer.should_receive(:name).and_return('Joe customer')
# bad - very tightly bound to implementation

customer.stub(:name).and_return('Joe customer')
# also tighly bound to implementation
  • Stubs are often used like mocks, mocks used like stubs.
  • We verify stubs by checking state after an interaction.
  • We tell mocks to verify interactions.
  • Sometimes stubs just make the system run.

When are method stubs helpful?

Isolation from non-determinism: Simulate random value geneators or Time.now.

Isolation from external depedencies: e.g. external database or network. Have gave anexample or an ActiveMerchant test that takes 1.5s to run, and stubbed out gateway.stubs(:authorize).returns(AM:Billing:Response.new(true, ‘ignore’)

Polymorphic collaborators: e.g. employee that knows how to pay itself, uses a strategy. paymet_strategy = mock() employee = E.new(p_s)
p_s.expects(:pay)
employee.pay

mixins/plugins

When are messsage expectations helpful?

side effects: background processing

caching: only call a network zipcode lookup once

validator = mock()
zipcode = Zipcode.new("01234", validator)
validator.should_receive(:valid?).with("01234").once
zipcode.valid?
zipcode.valid?

interface discovery: tool to discover the parts of the system that you haven’t really worked out yet. Mock something out that doesn’t exist yet, while designing its interface.

Isolation Testing

All of these concepts are Isolation Testing – testing an object in isolation from others. This is a good fit when you have lots of little objects (ravioli code, as opposed to spaghetti code).

Isolation Testing in Rails

Rails is calzone code. Three layers: View Controller Model. These 3 layers are not the whole picture: browser, router, database. Standard rails testing:

  • Unit tests: Testing in isolation. Test model classes (repositories), model objects, database.
  • Functional tests: 2 or more non-trivial components work together. Test model classes, model objcets, database, views, controllers.
  • Integration tests: Test model classes, model objects, database views controllers, routing/sessions.
    This is !DRY

Mocking and stubbing you can do in Rails

Partials in view specs:

before :each do
  template.stub(:render).with(:partial => anything)
end

...

template.should_receive(:render).with(:partial => 'nav')

Conditional branches in controllers: Stub new and save! methods of models.

Dave has a new project stubble on github: You will need to build RSpec locally to use this for now.

stubbing(Registration) do
#  Stubs ActiveRecord finder and save methods on model

Chains are a new RSpec feature: user.stub_chain – some people say this is a test no-no, use with caution.

Guidelines, concerns & Common Pitfalls

  • Keep things simple
  • Try to avoid tight coupling
  • Complex setup is a red flag for design issues
  • Don’t stub and mock the object that you are testing
  • Concern: impedes refactoring (but some say refactoring is improving design without changing behavior, so tests should not change. This really depends what level you are refactoring at).
  • Concern: false positives

Comments
Post a Comment

Your Information (Name required. Email address will not be displayed with comment.)

* Copy This Password *

* Type Or Paste Password Here *