<div><span class="gmail_quote">On 23/09/06, <b class="gmail_sendername">Paul Butcher</b> &lt;<a href="mailto:paul@82ask.com">paul@82ask.com</a>&gt; 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 &quot;stubs&quot; 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>&nbsp;&nbsp;def test_two_stubs<br>&nbsp;&nbsp;&nbsp;&nbsp;t = Time.now - 60<br>&nbsp;&nbsp;&nbsp;&nbsp;
Time.stubs(:now).returns(t)<br><br>&nbsp;&nbsp;&nbsp;&nbsp;start_time = Time.now<br><br>&nbsp;&nbsp;&nbsp;&nbsp;t += 20<br>&nbsp;&nbsp;&nbsp;&nbsp;Time.stubs(:now).returns(t)<br><br>&nbsp;&nbsp;&nbsp;&nbsp;end_time = Time.now<br><br>&nbsp;&nbsp;&nbsp;&nbsp;assert_equal end_time - start_time, 20<br>&nbsp;&nbsp;end<br><br>But it fails with:
<br><br>&nbsp;&nbsp;1) Failure:<br>test_two_stubs(MochaTest) [mochatest.rb:19]:<br>&lt;0.0&gt; expected but was<br>&lt;20&gt;.<br><br>I can create a test which works as I intend:<br><br>&nbsp;&nbsp;def test_lambda<br>&nbsp;&nbsp;&nbsp;&nbsp;t = Time.now - 60<br>
&nbsp;&nbsp;&nbsp;&nbsp;Time.stubs(:now).returns(lambda { t })<br><br>&nbsp;&nbsp;&nbsp;&nbsp;start_time = Time.now<br><br>&nbsp;&nbsp;&nbsp;&nbsp;t += 20<br><br>&nbsp;&nbsp;&nbsp;&nbsp;end_time = Time.now<br><br>&nbsp;&nbsp;&nbsp;&nbsp;assert_equal end_time - start_time, 20<br>&nbsp;&nbsp;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;">&nbsp; def test_two_stubs_with_parameter_block</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">&nbsp;&nbsp;&nbsp; t = Time.now - 60
</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">&nbsp;&nbsp;&nbsp; context = :start</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">
&nbsp;&nbsp;&nbsp; Time.stubs(:now).with { context == :start }.returns(t)</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">&nbsp;&nbsp;&nbsp; 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;">&nbsp;&nbsp;&nbsp; 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;">&nbsp;&nbsp;&nbsp; context = :finish<br><br style="font-family: courier new,monospace;"></span><span style="font-family: courier new,monospace;">
&nbsp;&nbsp;&nbsp; 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;">&nbsp;&nbsp;&nbsp; assert_equal end_time - start_time, 20</span>
<br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">&nbsp; end</span><br style="font-family: courier new,monospace;">&nbsp; <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;">&nbsp; def test_two_stubs_consecutive_return_values</span>
<br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">&nbsp;&nbsp;&nbsp; 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;">&nbsp;&nbsp;&nbsp; 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;">
&nbsp;&nbsp;&nbsp; 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;">&nbsp;&nbsp;&nbsp; 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;">&nbsp;&nbsp;&nbsp; assert_equal end_time - start_time, 20</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">
&nbsp; 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>