<div><span class="gmail_quote">On 23/09/06, <b class="gmail_sendername">Paul Butcher</b> <<a href="mailto:paul@82ask.com">paul@82ask.com</a>> wrote:</span><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">
I'm using "stubs" to test some realtime functions, to control exactly which<br>time is returned from Time.now. I would expect the following test to pass:<br><br> def test_two_stubs<br> t = Time.now - 60<br>
Time.stubs(:now).returns(t)<br><br> start_time = Time.now<br><br> t += 20<br> Time.stubs(:now).returns(t)<br><br> end_time = Time.now<br><br> assert_equal end_time - start_time, 20<br> end<br><br>But it fails with:
<br><br> 1) Failure:<br>test_two_stubs(MochaTest) [mochatest.rb:19]:<br><0.0> expected but was<br><20>.<br><br>I can create a test which works as I intend:<br><br> def test_lambda<br> t = Time.now - 60<br>
Time.stubs(:now).returns(lambda { t })<br><br> start_time = Time.now<br><br> t += 20<br><br> end_time = Time.now<br><br> assert_equal end_time - start_time, 20<br> end<br><br>But I'd be interested to understand why the first version doesn't.
<br></blockquote></div><br>Hi Paul,<br><br>The first version doesn't work, because the second stub expectation doesn't replace the first. When the end_time call to <span style="font-family: courier new,monospace;">Time.now
</span> comes in, it is matched to the first expectation and so returns the first value of t. I agree that this is not what you would expect and it's been on my todo list for a while. It hasn't made it to the top, because there are ways round it as you have demonstrated. I would probably use the same technique as you, but you might be interested to see a couple of other possibilities...
<br><br>The first one makes use of the fact that expectations match based on parameters as well as method name. Even though <span style="font-family: courier new,monospace;">Time.now</span> doesn't take any parameters, you can supply a block which returns true or false depending on whether it should match...
<br><br><span style="font-family: courier new,monospace;"> def test_two_stubs_with_parameter_block</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;"> t = Time.now - 60
</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;"> context = :start</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">
Time.stubs(:now).with { context == :start }.returns(t)</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;"> Time.stubs(:now).with { context == :finish }.returns(t + 20)
</span><br style="font-family: courier new,monospace;"><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;"> start_time = Time.now</span><br style="font-family: courier new,monospace;">
<br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;"> context = :finish<br><br style="font-family: courier new,monospace;"></span><span style="font-family: courier new,monospace;">
end_time = Time.now</span><br style="font-family: courier new,monospace;"><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;"> assert_equal end_time - start_time, 20</span>
<br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;"> end</span><br style="font-family: courier new,monospace;"> <br>The second one makes use of a recent change in HEAD (not released in the gem), which allows you to specify consecutive return values. Although this won't be useful if there are many calls to
<span style="font-family: courier new,monospace;">Time.now</span>...<br><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;"> def test_two_stubs_consecutive_return_values</span>
<br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;"> t = Time.now - 60</span><br style="font-family: courier new,monospace;"><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;"> Time.stubs(:now).returns(t, t + 20)</span><br style="font-family: courier new,monospace;"><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">
start_time = Time.now</span><br style="font-family: courier new,monospace;"><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;"> end_time = Time.now</span><br style="font-family: courier new,monospace;">
<br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;"> assert_equal end_time - start_time, 20</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">
end</span><br style="font-family: courier new,monospace;"><br clear="all">I hope that helps.<br>-- <br>James.<br><a href="http://blog.floehopper.org">http://blog.floehopper.org</a>