I'm using Ruby 3.2.2 with Rails 7.0.5.
I'm writing a unit test some code while mocking/stubbing a utility class that uses various class methods.
It roughly looks like this:
class MyUtilityClass
def self.foo
# Does something...
end
def self.bar
# Does something else...
end
end
class MyTestTarget
def run_foo
MyUtilityClass.foo
end
end
I want to test that when I call run_foo
it calls foo
but not bar
in MyUtilityClass
. So I need to stub both foo
and bar
as part of my test.
I know how to stub methods like this:
test 'calls foo' do
mock_foo = Minitest::Mock.new
mock_foo.expect :call, nil, []
MyUtilityClass.stub :foo, mock_foo do
t = MyTestTarget()
t.run_foo
end
mock_foo.verify
end
What is the most elegant/best practice way to test that bar()
was not called as part of this test case?
Warning at the end.
So, the ugly answer your actual question, I believe the only way with Minitest::Mock
is to create a mock for your :bar
and then assert that .verify
DOES raise MockExpectationError
.
...but the much nicer answer to your underlying question is that the awkward API and lack of features in the built-in mocking is why gems like mocha
exist, and I'd strongly recommend it's worth switching to even if for just this one use case:
test 'calls foo not bar' do
MyUtilityClass.expects(:foo).once
MyUtilityClass.expects(:bar).never
MyTestTarget.new.run_foo
end
Hopefully you know how fickle testing that something has NOT been called can be. Eg. if someone later adds a call to bar
inside foo
then because you're mocking foo
in your test, then bar
will still not be being called (in your test) even though it IS being called in your actual code.