README.md in mocktail-0.0.6 vs README.md in mocktail-1.0.0

- old
+ new

@@ -578,17 +578,32 @@ # def fill(water_type, arg) # end ``` From there, you can just copy-paste the provided method stub as a starting point -for your new method. +for your new method: -#### `nil` values returned by faked methods +```ruby +class IceTray + def fill(water_type, amount) + end +end +``` -Suppose you go ahead and implement the `fill` method above and configure a -stubbing: +### Unexpected nils with Mocktail.explain_nils +Is a faked method returning `nil` and you don't understand why? + +By default, methods faked by Mocktail will return `nil` when no stubbing is +satisfied. A frequent frustration, therefore, is when the way `stubs {}.with {}` +is configured does not satisfy a call the way you expected. To try to make +debugging this a little bit easier, the gem provides a top-level +`Mocktail.explain_nils` method that will return an array of summaries of every +call to a faked method that failed to satisfy any stubbings. + +For example, suppose you stub this `fill` method like so: + ```ruby ice_tray = Mocktail.of(IceTray) stubs { ice_tray.fill(:tap_water, 30) }.with { :normal_ice } ``` @@ -596,24 +611,26 @@ But then you find that your subject under test is just getting `nil` back and you don't understand why: ```ruby def prep - ice = ice_tray.fill(:tap_water, 50) # => nil - glass.add(ice) + ice = ice_tray.fill(:tap_water, 50) + glass.add(ice) # => why is `ice` nil?! end ``` -You can pass that `nil` value to `Mocktail.explain` and get an -`UnsatisfiedStubExplanation` that will include both a `reference` object to explore - as well a summary message: +Whenever you're confused by a nil, you can call `Mocktail.explain_nils` for an +array containing `UnsatisfyingCallExplanation` objects (one for each call to +a faked method that did not satisfy any configured stubbings). +The returned explanation objects will include both a `reference` object to +explore as well a summary `message`: + ```ruby def prep - ice = ice_tray.fill(:tap_water, 50).tap do |wat| - puts Mocktail.explain(wat).message - end + ice = ice_tray.fill(:tap_water, 50) + puts Mocktail.explain_nils.first.message glass.add(ice) end ``` Which will print: @@ -624,20 +641,28 @@ The actual call: fill(:tap_water, 50) +The call site: + + /path/to/your/code.rb:42:in `prep' + Stubbings configured prior to this call but not satisfied by it: fill(:tap_water, 30) ``` +The `reference` object will have details of the `call` itself, an array of +`other_stubbings` defined on the faked method, and a `backtrace` to determine +which call site produced the unexpected `nil` value. + #### Fake instances created by Mocktail -Any instances created by `Mocktail.of` or `Mocktail.of_next` can also be passed -to `Mocktail.explain`, and they will list out all the calls and stubbings made -for each of their fake methods. +Any instances created by `Mocktail.of` or `Mocktail.of_next` can be passed to +`Mocktail.explain`, and they will list out all the calls and stubbings made for +each of their fake methods. Calling `Mocktail.explain(ice_tray).message` following the example above will yield: ``` @@ -660,10 +685,12 @@ If you've called `Mocktail.replace()` on a class or module, it can also be passed to `Mocktail.explain()` for a summary of all the stubbing configurations and calls made against its faked singleton methods for the currently running thread. +Imagine a `Shop` class with `self.open!` and `self.close!` singleton methods: + ```ruby Mocktail.replace(Shop) stubs { |m| Shop.open!(m.numeric) }.with { :a_bar } @@ -702,9 +729,13 @@ This one's simple: you probably want to call `Mocktail.reset` after each test, but you _definitely_ want to call it if you're using `Mocktail.replace` or `Mocktail.of_next` anywhere, since those will affect state that is shared across tests. + +Calling reset in a `teardown` or `after(:each)` hook will also improve the +usefulness of messages returned by `Mocktail.explain` and +`Mocktail.explain_nils`. ## Acknowledgements Mocktail is created & maintained by the software agency [Test Double](https://twitter.com). If you've ever come across our eponymously-named