Please Mock me :-) Rspec

Hi all,

I’m trying to understand rspec.

questions:-

  1. Can/should I use mock in model tests. I’m thinking to mock out
    models external to the test ie parent/child objects etc

  2. so assuming answer to question 1 is yes/yes how do i implement
    it. i tried…

company = mock_model(Company)
@listing = company.listing.create

running the test get this error

Spec::Mocks::MockExpectationError in ‘Listing should be valid’
Mock ‘Company_1000’ received unexpected message :listing with (no args)

so i should be using the

my_mock.should_receive(:listing).with(:no_args)

or so i thought i then got

NoMethodError in ‘Listing should be valid’
You have a nil object when you didn’t expect it!
The error occurred while evaluating nil.create

so maybe it’s not possible to do this? or maybe i need to pass
somthing back? but what? i don’t really want to pass back a mock
listing i want to test that it is created in the database properly

any pointers appreciated
nathan

On Wed, Feb 27, 2008 at 11:58 AM, nathan sharkey
[email protected] wrote:

  1. so assuming answer to question 1 is yes/yes how do i implement it. i

The error occurred while evaluating nil.create

so maybe it’s not possible to do this? or maybe i need to pass somthing
back? but what? i don’t really want to pass back a mock listing i want to
test that it is created in the database properly

This is not really an rspec question - it’s a more general “mocking
AR” question.

When you do this:

company = mock_model(Company)

you’re creating a mock object, not an instance of Company. The
mock_model method adds some things to the mock object that are
standard across AR objects, but it is still a mock object. Since
:listing does not belong to AR::Base, you have to set up a stub or a
message expectation for it - as you tried to do.

There is a meme, axiom, whatever, in TDD that says “test YOUR code,
not other people’s.” What you’re doing here is testing other people’s
code and you don’t really need to do that. We all know that
model.association.create works, and to test it you have to go through
crazy mocking shenanigans like this:

listings = mock(“listings”)
listing = mock_model(Listing)
company.should_receive(:listings).and_return(listings)
listings.should_receive(:create).and_return(listing)

Oy vey!

This is a case where I, for one, either allow DB access or use a tool
like model_stubbing. I haven’t tried NullDB yet but seems pretty cool
too.

I do mock the hell out of AR from controller, view and helper specs.
None of those ever go near a DB. But model specs are a gray area - no
one right answer for all cases IMO.

HTH,
David

Hi David,

Cheers for that I think I understand better how to mock. It makes
sense not to test active record but my motivations were different I
was trying to set-up records to test the validation rules I had created.

is something like the following considered code to test?

validates_presence_of :title, :if => published?
validates_existence_of :company
validates_existence_of :location, :if => published?

def published?
state == “published”
end

and if so is it possible/advisable mock the company/location but not
the listing? I think your suggesting it isn’t possible to do this
but… maybe I can mock Company and Location and create Listing as so

@company = mock_model(Company)
@location - mock_model(Listing)
company.should_receive(:id).and_return(1)
listings.should_receive(:id).and_return(1)
@listing = Lisitng.new(:company_id => @company.id, :location_id =>
@location.id

Are there any multi model examples of applications out there with
Rspec tests that I could study or Books maybe? I think this would
help me greatly understand what to test and what not to and how tests
are de coupled correctly. I’d love to see one made with stories
too, I’ve been writing stories but haven’t tried to implemented them
yet, figured it would make sense to understand model tests and then
work my way up… stories fascinate me because they get me thinking
about how it will look and feel to the user not just the behaviour.
Maybe I should be doing things top down from stories but I feel that
is a bit advanced for now :slight_smile:

cheers again for your input…
Nathan

On 27 Feb 2008, at 22:07, David C. wrote:

  1. Can/should I use mock in model tests. I’m thinking to mock out
    models
    external to the test ie parent/child objects etc

  2. so assuming answer to question 1 is yes/yes how do i implement
    it. i
    tried…

company = mock_model(Company)
@listing = company.listing.create

cool I hadn’t thought of doing a Company.new like that but makes
total sense… and i like

@listing.should_not be_valid_with(valid_attributes).less(:title)

it reads very nicely :slight_smile:

unfortunately i still doesn’t work, so no fooling
validates_existence_of plugin that way

‘a published Listing should be valid with valid attributes’ FAILED
Listing expected to be valid but had errors:
Company does not exist

also

‘a published Listing should be invalid without a title’ FAILED
Matcher does not support should_not.
See Spec::Matchers for more information
about matchers.

am i missing a matcher or should i be writing one?

cheers Nathan

On Thu, Feb 28, 2008 at 4:04 AM, nathan sharkey
[email protected] wrote:

validates_existence_of :company
@company = mock_model(Company)
@location - mock_model(Listing)
company.should_receive(:id).and_return(1)
listings.should_receive(:id).and_return(1)
@listing = Lisitng.new(:company_id => @company.id, :location_id =>
@location.id

You don’t really need mocks at all for describing the validation
behaviour. Just create a listing, get it into the state you want and
expect it to be valid or invalid as appropriate:

describe “a published Listing” do
def valid_attributes
{:title => “A Great Read”,
:company => Company.new,
:listing => Listing.new}
end

before(:each) do
@listing = Listing.new(valid_attributes)
@listing.stub!(:published?).and_return(true)
end

it “should be valid with valid attributes” do
@listing.should be_valid
end

it “should be invalid without a title” do
@listing.title = nil
@listing.should_not be_valid
end

… etc
end

You could also write a custom matcher that lets you do stuff like this:

@listing.should_not be_valid_with(valid_attributes).less(:title)

Come to think of it, maybe we should just add that to rspec_on_rails!
(Lighthouse - Beautifully Simple Issue Tracking)

Cheers,
David

Are there any multi model examples of applications out there with
Rspec tests that I could study or Books maybe?

I am working on an RSpec book that will have some material on Rails.
This issue will definitely be addressed, but as I said before -
there’s no one right answer, so don’t expect silver bullet solutions.

In the mean time, there are a few good books on TDD, which is part of
the basis for BDD. In fact, if you read them you’ll see things like
“this is not a book about testing” and “focus on behaviour.” Here are
a couple of recommendations:

Test-Driven Development by Example (Kent Beck)
Test-Driven Development, a Practical Guide (Dave A.)

The won’t teach you about Rails directly, but they do address
decoupling and finding a related balance.

I think this would
help me greatly understand what to test and what not to and how tests
are de coupled correctly. I’d love to see one made with stories
too,

There will be material in my book on Stories. Early in the book there
is a worked example, developing a small command line application using
stories together with object specs.

I’ve been writing stories but haven’t tried to implemented them
yet, figured it would make sense to understand model tests and then
work my way up… stories fascinate me because they get me thinking
about how it will look and feel to the user not just the behaviour.
Maybe I should be doing things top down from stories but I feel that
is a bit advanced for now :slight_smile:

That’s the trick. Often things that produce a simple and clear result
have to do some complex things under the hood. This is true of all of
the components in Rails, and certainly true of RSpec stories as well.

cheers again for your input…

My pleasure.

Cheers,
David

OK cheers David I’ll do that

thanks for all your help :slight_smile:

On Thu, Feb 28, 2008 at 12:05 PM, nathan sharkey
[email protected] wrote:

validates_existence_of plugin that way
I’m not sure what plugin you mean, but I don’t maintain it. I’d
recommend checking with its authors about whether they had
mocking/stubbing in mind.

Cheers,
David

Mocks Aren't Stubs is a great
read. Decide yourself if you should be mocking at all or not.

On Fri, Feb 29, 2008 at 3:25 PM, nathan sharkey
[email protected] wrote:

I’m not sure what plugin you mean, but I don’t maintain it. I’d
recommend checking with its authors about whether they had
mocking/stubbing in mind.

Cheers,
David


Cheers!

I know yr hoping to use that article as a bully pulpit but I just wanted
to
point out one phrase:

“So if mockist testing sounds appealing to you, I’d suggest giving it a
try.”

Nowhere in the article does Fowler say “mocking is bad” as you imply
with yr
“[d]ecide yourself if you should be mocking at all or not.” :wink: Just had
to
clear that up.

RSL

I confess i had stumbled across that article previously but passed it
over, cos it was too wordy :wink:

just read it though and it’s great i understand so much more now I
hadn’t even been aware of a classic/mockist distinction. One
interesting aspect is that as a beginner to testing i was in the
mindset that i had to get all my tests for the model right before i
could work my way out to the controller’s and views. now i realise
you can work in to out or out to in per feature not per model. Also
It hadn’t even occurred to me that you could develop your ui before
ever developing the models below it, i guess stories will be great
for this. i don’t think i would want to do that but it’s interesting
to note that it can be done by using mocks.

one question which maybe you can help clarify for me. there is a
line in the article

“It’s at this point that I should stress that whichever style of test
you use, you must combine it with coarser grained acceptance tests
that operate across the system as a whole. I’ve often come across
projects which were late in using acceptance tests and regretted it.”

whats an acceptance test, is it an integration test by another name?

cheers
nathan