Rspec questions: same file? mocks objects as params?

I’m just getting started with rspec. Two questions:

  1. Should the rspec be in the same file as the production code? The
    examples on the rspec site seem to indicate they should be in a separate
    file but I wanted to double check.

  2. If I use mocks, am I supposed to pass them as parameters to my
    production code?

If my code looked like:

def read()
db = database.instance()
db.execute(…)
end

and I want to do a mock database connection do I have to write the
production code like:

def read(db=database.instance())
db.execute(…)
end

and then call it with read(my_mock) ?

On Nov 14, 2007 11:02 AM, David W. [email protected] wrote:

I’m just getting started with rspec. Two questions:

  1. Should the rspec be in the same file as the production code? The
    examples on the rspec site seem to indicate they should be in a separate
    file but I wanted to double check.

Specs should be separate. In a Rails app there’s a spec dir that
parallels your app dir. If you’re writing a Ruby app from scratch
then you’ll need to create it yourself. But definitely stick specs in
separate files from production code.

and I want to do a mock database connection do I have to write the
production code like:

def read(db=database.instance())
db.execute(…)
end

and then call it with read(my_mock) ?

You can do it that way, or you can stub the call to #instance and have
it return the mock.

Also, without knowing anything about your code :slight_smile: I would be more
likely to pass the datastore into the constructor:

class Person
def initialize(datastore)
@datastore = datastore
end

def read
conn = @datastore.instance
conn.execute(…)
end
end

Then your spec would look something like:

describe Person, " reading a record" do
before(:each) do
@mock_connection = mock(“db connection”)
@mock_pool = stub(“connection pool”, :instance => @mock_connection)

@person = Person.new @mock_pool

end

it “should get a connection” do
@mock_pool.should_receive(:instance).and_return @mock_connection
@person.read
end

it “should select data from the database” do
@mock_connection.should_receive(:execute).with(…)
@person.read
end
end

Which is sort of ugly because you have a mock returning a mock, but
such is life with a singleton :slight_smile:

Pat

  1. If I use mocks, am I supposed to pass them as parameters to my
    production code?

If I understand correctly you shouldn’t change your production code at
all. The goal of mocks, basically, is that they enable you to cleanly
separate the specs from the production code. With the example stuff
Pat wrote, you get that. You want to set up the mocks to parallel
whatever is happening in the production code that you don’t actually
want run by the specs - hitting the database is part of that because
the DB gives you a bottleneck and speed really matters when it comes
to tests (you’ll only actually use the tests (or specs) if they’re
fast). But the point is you shouldn’t change production code to do
anything with a mock. The whole point of a mock is that it allows your
tests or specs to run as if the production code was behaving as
normal.


Giles B.

Podcast: http://hollywoodgrit.blogspot.com
Blog: http://gilesbowkett.blogspot.com
Portfolio: http://www.gilesgoatboy.org
Tumblelog: http://giles.tumblr.com

On Nov 14, 2007 6:08 PM, Giles B. [email protected] wrote:

  1. If I use mocks, am I supposed to pass them as parameters to my
    production code?

If I understand correctly you shouldn’t change your production code at all.

Well, not quite. If you’re retrofitting tests onto existing code,
you’ll often need to change the production code to work with mocks.
That’s because most code that isn’t written with testability in mind
tends to be too coupled, because it’s just easier to write code that
way. So you certainly could have to break those dependencies when
you’re writing tests after the fact.

But you’re right, the whole point of mocks is to allow you to swap in
a different object with the same interface. Mocking isn’t a silver
bullet of course…code that’s easy to mock isn’t necessarily
well-design, but in general there are fewer dependencies - a Good
Thing.

Pat