T
Thiago Arrais
Has anyone tried to mock whole classes (instead of mocking only the objects=
)?
Classes are, like everything else in Ruby, just objects. This allows
us to mock them just like we would mock any other object. I have been
working on a Rails application (that will be shared with you as soon
as I get it translated, I promise) in which I needed to do exactly
that.
The class I wanted to mock is responsible for communicating to my
back-end database and fetching the appropriate objects (instances of
itself). The object-finding functionality is implemented as class
level methods. If I need the N latest headlines from a reporter named
'johnson', I just need to call `Headline.latest(N, "johnson").
If I need to test a class that needs to do a Headline.latest call as
part of its job, I don't want to populate the database with real data
(and slow down my tests as I wait for a connection) because I mostly
trust that Headline works. It has its own tests to assure that. So I
mock the Headline class to make sure my class under test makes the
correct calls.
I have come up with a simple way to that in Ruby and I am mostly
satisfied with the results, but I would like to get some feedback from
the community. The source is here:
----
class CacheReporter < MotiroReporter
def initialize(headlines_source=3DHeadline)
@headlines_source =3D headlines_source
end
def latest_headlines
return @headlines_source.latest(3, 'mail_list')
end
end
class CacheReporterTest < Test::Unit::TestCase
def test_reads_from_database
FlexMock.use do |mock_headline_class|
mock_headline_class.should_receivelatest).
with(3, 'mail_list').
once
reporter =3D CacheReporter.new(mock_headline_class)
reporter.latest_headlines
end
end
end
----
The main change here can be seen on the CacheReporter constructor. If
I were not testing, it wouldn't even be written, I would just use the
Headline class wherever I wanted. But instead of directly using the
Headline class inside its methods, it receives it on the constructor.
This is what allows us to mock the behavior.
Has anyone done anything similar? Can the code be made simpler?
Cheers,
Thiago Arrais
)?
Classes are, like everything else in Ruby, just objects. This allows
us to mock them just like we would mock any other object. I have been
working on a Rails application (that will be shared with you as soon
as I get it translated, I promise) in which I needed to do exactly
that.
The class I wanted to mock is responsible for communicating to my
back-end database and fetching the appropriate objects (instances of
itself). The object-finding functionality is implemented as class
level methods. If I need the N latest headlines from a reporter named
'johnson', I just need to call `Headline.latest(N, "johnson").
If I need to test a class that needs to do a Headline.latest call as
part of its job, I don't want to populate the database with real data
(and slow down my tests as I wait for a connection) because I mostly
trust that Headline works. It has its own tests to assure that. So I
mock the Headline class to make sure my class under test makes the
correct calls.
I have come up with a simple way to that in Ruby and I am mostly
satisfied with the results, but I would like to get some feedback from
the community. The source is here:
----
class CacheReporter < MotiroReporter
def initialize(headlines_source=3DHeadline)
@headlines_source =3D headlines_source
end
def latest_headlines
return @headlines_source.latest(3, 'mail_list')
end
end
class CacheReporterTest < Test::Unit::TestCase
def test_reads_from_database
FlexMock.use do |mock_headline_class|
mock_headline_class.should_receivelatest).
with(3, 'mail_list').
once
reporter =3D CacheReporter.new(mock_headline_class)
reporter.latest_headlines
end
end
end
----
The main change here can be seen on the CacheReporter constructor. If
I were not testing, it wouldn't even be written, I would just use the
Headline class wherever I wanted. But instead of directly using the
Headline class inside its methods, it receives it on the constructor.
This is what allows us to mock the behavior.
Has anyone done anything similar? Can the code be made simpler?
Cheers,
Thiago Arrais