Skip to content

Instantly share code, notes, and snippets.

@jamesgary
Last active July 26, 2022 09:06
Show Gist options
  • Save jamesgary/5491390 to your computer and use it in GitHub Desktop.
Save jamesgary/5491390 to your computer and use it in GitHub Desktop.
The Magic Tricks of Testing - Sandi Metz - RailsConf2013

The Magic Tricks of Testing

Sandi Metz

  • Many people say "I hate my tests"

  • They kill your productivity when they're slow

  • A little change can break your tests (even if they shouldn't)

  • They're expensive

  • They are misery incarnate

  • Just delete some tests

    • You may have too many tests testing the wrong tests
  • Unit Tests goals (not mentioning integration/end-to-end tests)

    • Thorough
    • Stable
    • Fast
    • Few (must be shortest possible proof)
  • Focus on messages

  • Objects are simple-minded black boxes (imagine a space capsule)

  • The object under test receives incoming messages, then sends outgoing messages

    • Messages can be sent from itself to itself, but let's ignore them
  • Query messages return something and change nothing

  • Command messages return nothing, and changes something

  • We conflate commands and queries at your peril

  • Hidden side effects are the bane of programmers

6 types of messages (Query/Command X Incoming/Outgoing/Sent-to-self)

  • Incoming query messages

    • Wheel#diameter
    • Assert the value sent back
    • Test the interface, not the implementation
  • Incoming command messages

    • Gear#set_cog
    • Send the message, then assert the direct public side effect
  • Receiver of incoming message has sole responsibility for asserting the result / side affects

  • Don't test private methods

    • It adds no safety, yet breaks when implementation changes
  • Outgoing query messages

    • (Same rules as 'Sent to Self')
    • Do not test outoging query messages (as long as there are no visible sie affects)
  • Outgoing command message

    • Might assert the side effect (such as the state of the db)
      • BUT this creates a dependency on a distant side effect
      • This is an integration test
    • Instead, inject a mock that expects a message
      • This depends on the interface and message passings
  • Caveat: Break a rule if it saves $$$ during development

  • BUT aren't they fragile?

  • Honor the contract

    • Ensure test doubles stay in sync with the API
  • There's plenty of ways to use mocks/stubs that aren'te fragile

    • bogus, quacky, rspec-fire, .and_call_original
  • Be a minimalist

  • Get proof enough

  • Use good judgement, so you can break them when you need to

  • Don't test more than once

  • Test the interface

  • Trust collaborators

  • Insist on simplicity

  • Practice! So one day you can love your tests

@aesyondu
Copy link

A thousand words, for reference:

unit-testing-matrix

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment