On Tue, Sep 23, 2008 at 3:39 AM, CarmineM [email protected]
wrote:
anything()).and_yield(mock_result(:successful? => true),
Without knowing everything about your code, that looks almost there!
You’re
basically specing that when the create action is called (from do_verb):
- authenticate_with_open_id should get called with certain parameters
- When it does get called, have it yield certain other parameters to
its
block
- User.create_with_role gets called and returns something returned by
create_operator_user
I would ask:
- What arguments should User.create_with_role be called with? These
should
be specified (tested).
- What is the return value of User.create_with_role, and what should be
done with it? Answer: it returns a user, which should end up getting
assigned to the controller’s @user. This specification is accomplished
with
assigns[:user].should == <the mock user object you’re returning from
User.create_with_role>.
As far as “the way” to use RSpec in situations like this, I use TDD/BDD.
Basically, this means that we don’t write any code without a failing
test.
Think about that. It’s a pretty weird concept. But it works.
One way to achieve this ex post facto would be to comment out all your
controller code. Write the simplest spec that describes something you
want
to have happen. It will fail. Then comment back in the code (and just
the
code) to make the test pass. After it passes, see if the commented in
code
expresses its intent well (in other words, clean it up if necessary).
Then
think of another test (or “description of behavior”) to write. It
fails,
you make it pass, you clean it up. And so on. Continue this cycle until
you
can’t think of any more tests - in other words, everything you want the
code
to do has been described/verified/tested.
This has several benefits: 1) You take tiny steps, which are so much
easier
than any other kind of steps. 2) You make sure you haven’t missed any
specifications, because every line of code is described before it’s even
been written, and 3) You move away from thinking “is the code I just
wrote
correct?” to “what should this code I’m about to write actually
accomplish”?
Also, try to match RSpec’s grammar with regard to the “describe” and
“it”
blocks, such that they stand alone as documentation (though I can never
remember the RSpec command to produce it). In the above spec, you’re
saying
“being an administrator, it should create a new user using OpenID
authentication.” In reality, what you want to describe is what happens
when
someone POSTs data to your create action. That may have further context
applied, such as “when the poster is an administrator”.
What line of code does all this describe? The do_verb call. So if I were
writing this from scratch, that’s the first line of code I’d write in
the
spec (presumably, something like ‘post :create, :identity_url =>
‘asdf’’).
I’d run this line of code and it would fail (I think) because that
action
doesn’t exist in the controller (because we commented it out). So the
next
step would be to do the simplest thing that could make the test pass;
obviously, defining the controller method (without anything in it).
What should the next test be? Well, you could test that
authenticate_with_open_id is called. So you’d set up an expectation on
that
method: @controller.should_receive(authenticate_with_open_id). You’d run
the
test, it would fail, and then you’d add the call. Now, what parameters
should authenticate_with_open_id receive? Specify them. Test fails. Add
them. Test passes.
If you go through this process with every single line of code you write,
not
only do the tests become obvious as you go along, but so does the code
under
test. You might find that (as in your original code), you have to set up
a
lot of tests on what happens to the new user. As a result, you might
realize
that the controller shouldn’t care about these details, and that you
should
write User.create_with_role (for which you’ll eventually write its own
tests). This is an example of how when testing is tedious or difficult,
it
may point to the code not being structured correctly.
Good lord; listen to me rattle on. I’m pretty confident in everything
I’ve said here, but it’s been explained a lot better by others. Perhaps
the
best way to get more information on how to use RSpec is to google TDD
and/or
BDD. And stay on this list, paying especially attention to posts by
people
like David and Pat (as well as others).
Good luck!
///ark