Skip to content

Instantly share code, notes, and snippets.

@jondkinney
Last active December 23, 2015 18:19
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jondkinney/6674458 to your computer and use it in GitHub Desktop.
Save jondkinney/6674458 to your computer and use it in GitHub Desktop.

What is a unit in TDD - a unit of work. A use-case in the system.

http://cl.ly/RY8x

3 options for a unit of work:

  • Return Value / Exception
  • Noticable State Change (adding a user for example)
  • 3rd Party Call (only place to use mock objects?)

More than just testing the implementation of the code that you're writing, or querying the database to check that a user was created... instead, test that the user can login to ensure that the code actually works.

  • So to me this means use cucumber to do that high level test, but drive the implementation with BDD mock based tests on the inside

Tripple a's of testing

  • Arrange
  • Act
  • Assert

Getting rspec rollin:

$ rspec --init

Creates:

  • spec folder
  • spec/spec_helper.rb
  • .rspec in the root of the app (default options for running things locally)

guard -c

  • Always cleans the screen before it runs

Always try to recreate a bug with a test before fixing it.

let is a hinderance to productivity in reading tests (just define methods instead, which are still lazy loaded)

  • He uses hand made 'factory methods' instead of lets and befores, etc.
  • HOWEVER...sigh, then later he says that you can/should use lets for really long files, but only if you put them at the top of the file.

Rules of TDD

  1. No line of code without a failing test
  2. When you make the tests pass, solve it as simply as possible (but no simpler)
  3. Refactoring

Common questions in TDD

  • why write test before the code
    • See it fail
    • prevent regressions

Get your class to use the mock

  • Construction Injection
    • Pass in the dependency to the initialize method
  • Property Injection

Threads are considered an integration test becuase you don't have control over them

class FakeSlowLogger

  • Don't call it Mock or Stub when you hand write ruby methods that act as one or the other.
    • this way you can use it as either a mock or a stub in the tests in different contexts

Rule of thumb - no more than one mock object per spec

A mock object is anything that is fake and you assert against it.

A stub is an object that is fake that you don't assert against

A mock object is testing one end result

  • If you have multiple mock objects and one fails, every line below that will not execute and you won't have all the info you need to debug

He calls them 'isolation frameworks' where as everyone else calls them 'mock frameworks'

rSpec is a "strict" mocking framework - a mock expects to be told everything that will be called on it

You can't set it up to be more loose (non strict) and he calls it a 'hippy' mock

  • He says to use the gem 'bogus' because of this
    • HOWEVER - I think you can use the null_object pattern to solve this...

Bogus - has 'safe mocking' which will throw an error if a method doesn't exist, or you pass in the wrong number of parameters. This might be a better argument for using it than the previous 'you have to mock everything yourself' one (since I believe as_null_object solves that).

ADVANCED RSPEC

If StringCalculator doesn't have any dependencies - 'subject' in rspec will reference a new'ed up version of whatever we're describing

Subject is lazy loaded, so if it does have dependencies, you can control those in each context separately by overriding those dependencies as you go.

You can give a name to the subject too. BASICALLY ALWAYS DO THIS (my emphasis)

let memoizes the value unless you use let!. But all this does is memoize the result into a variable for multiple calls in THAT SINGLE EXAMPLE. It does NOT memoize it across examples (I believe he misspoke about this)

If you don't want to use 'it' and a string description (in rspec), you can use

specify { expect { calc.add('-1') }.to raise_error }

When describing a method on a class like #adding, define a method below the describe and re-use that in the tests so that if the implementation changes later, you can re-use that.

When using subject, you can use 'its' to assert on attributes of the subject

its { first_name.should == 'jon' }
its { last_name.should == 'kinney }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment