How to Mock

Who likes mocks?

Who thinks that mocks sucks?

Who knows what mock is?

simulated objects that mimic the behavior of real objects in controlled ways

Test Doubles

Confused about naming?

Read: https://8thlight.com/blog/uncle-bob/2014/05/14/TheLittleMocker.html

Why mocking?

Mock objects are meant to improve the expressiveness of code while reducing coupling

Problems

  • Change in implementation does not break tests
  • Change in implementation break tests

What is the most important rule about mocks?

Don't mock what you don't own

Own?

Do not mock any class you do not own. In fact, do not unit test any code that you do not 100% own.

Basically, if your code has a dependency that you don’t control, then you shouldn’t mock it because you can’t guarantee the interface will remain constant.

TDD is just as much about design that is is about test, when mocking an external API the test cannot be used to drive the design, the API belongs to someone else ; this third party can and will change the signature and behaviour of the API.

Own

  • your code

Don't

  • external API
  • database
  • file system
  • external library
  • etc

You don't own ActiveRecord

You about me

Integrated Tests Are A Scam

https://vimeo.com/80533536

I see strong correlation between high number of integration tests and design problems

Let's talk about code design

What is contract?

describe UmbrellaAssistant do
  it "asks whether service if it would be rainy" do
    whether_service = double
    
    assistant = UmbrellaAssistant.new(whether_service: whether_service)
    assistant.should_i_take_umbrella?

    expect(whether_service).to have_received(:will_be_rainy?)
  end
end

Collaboration test

describe UmbrellaAssistant do
  it "returns true if it will be rainy" do
    whether_service = double
    allow(whether_service).to receive(:will_be_rainy?).and_return(true)
    
    assistant = UmbrellaAssistant.new(whether_service: whether_service)
    expect(assistant.should_i_take_umbrella?).to be_true
  end

  it "returns false if it won't be rainy" do
    whether_service = double
    allow(whether_service).to receive(:will_be_rainy?).and_return(false)
    
    assistant = UmbrellaAssistant.new(whether_service: whether_service)
    expect(assistant.should_i_take_umbrella?).to be_false
  end
end

Expectation test

Mock as interface

Problems

  • Change in implementation does not break tests
  • Change in implementation break tests

The real benefit of isolated tests (...) is that those tests puts tremendous pressure on our designs

  • small classes
  • small methods
  • TDD

Push for design

Resources

http://blog.plataformatec.com.br/2015/10/mocks-and-explicit-contracts/

https://8thlight.com/blog/eric-smith/2011/10/27/thats-not-yours.html

 

Rubytapas #287, #289, #296, #312

How to Mock

By Jan Dudulski

How to Mock

  • 202