minitest and mocha, mocks and stubs
Debugger, an open-source project I’m working on has both Minitest and Mocha in its gemspec. For the last few months, I tried to only use Minitest until today, when I hit a limitation.
My goal was to test one method on
RdebugOptionParser, a class I extracted.
The method had to
require a file passed in as an argument. To make my test
a true unit test–that is, one that asserts on only the behavior I’m
implementing–I had to go beyond Minitest. The file I pass in as an argument
shouldn’t actually be required, I only want to test that
Minitest makes it easy to mock out an entire object. If you want to stub out a single method on an object, that should be easy, but I couldn’t get it working:
|# Excerpted from Minitest docs def test_stale_eh obj_under_test = Something.new refute obj_under_test.stale? Time.stub :now, Time.at(0) do # stub goes away once the block is done assert obj_under_test.stale? end end|
Even if I could get stubbing to work, I could only stub
require but not assert
that it was called. As I learned today, mocks are testing tools that allow you
to fake and set expectations on objects that you’re not testing directly. On
the other hand, stubs allow you to fake objects you aren’t directly testing.
So it was clear I wanted a mock. The only problem is that with Minitest, I
could only mock the entire
RdebugOptionParser object. Mocking
RdebugOptionParser would mean that I’d mock out the method I was actually
After an hour of searching for how to use Minitest to mock out one method on an object while keeping the rest of the object intact, I resigned to looking at options provided by other gems. Mocha’s syntax looked pretty clean, so I looked into adding it to the gemspec. Lo and behold, it was already there, huzzah!
The syntax is quite simple:
|RdebugOptionParser.instance.expects(:require).with('foo').returns(true) # Then call the method being tested call_rdebug_parse_with_arguments ["--require=foo"]|