ckreon ckreon - 5 months ago 17
Ruby Question

How to convert an Rspec test with stubs to Minitest

I'm trying to convert a test file from Rspec to Minitest, which up to this point has been going well (very simple tests thus far). But I've come across some stubs and I can't get them to function correctly.

Here is the original Rspec test:

it "takes exactly 1 second to run a block that sleeps for 1 second (with stubs)" do
fake_time = @eleven_am
Time.stub(:now) { fake_time }
elapsed_time = measure do
fake_time += 60 # adds one minute to fake_time
end
elapsed_time.should == 60
end


My attempt to convert that to Minitest:

it "takes exactly 1 second to run a block that sleeps for 1 second (with stubs)" do
fake_time = @eleven_am
Time.stub(:now, fake_time) do
elapsed_time = measure { fake_time += 60 }
elapsed_time.must_equal 60
end
end


And the method these are testing:

def measure(rep=1, &block)
start_time = Time.now
rep.times { block.call }
Time.now - start_time
end


The problem I'm having is that with Rspec, the stubs update dynamically with the method execution. When
fake_time
gets changed in the block,
Time.now
is immediately updated to correspond with that, meaning the final
Time.now
call is updated in my method, and it returns the appropriate difference (60).

With Minitest, I seem to override the
Time.now
response successfully, but it doesn't update with execution, so when
fake_time
gets adjusted,
Time.now
does not. This causes it to always return 0, as
start_time
and
Time.now
remain identical.

This is probably correct behavior for what it is, I'm just not sure how to get what I want out of it.

How do I make the Minitest stub act like the Rspec stub?

Answer

I received an answer from Chris Kottom on Reddit that I will share here.

The solution is to use a lambda:

Time.stub(:now, -> { fake_time }) do
    ...
end

This creates a dynamic stub that updates with your code execution.

If fake_time is a variable instead of a method (e.g. static vs. dynamic), you can represent this via:

Time.stub(:now, fake_time) do
    ...
end
Comments