[rspec-users] specs on private methods

Zach Dennis zach.dennis at gmail.com
Fri Jan 11 12:55:36 EST 2008


To add, all of our managers return LoginResult objects which contain
methods like:

 - successful?
 - user
 - message

In the controller our code will look like:

if login.successful?
  self.current_user = login.user
else
  flash[:error] = login.message
end

This has worked well because it allows each our types of logins to
generate an accurate login message based on the type of login. For
example when a user logs in from a session you don't need a message,
but after someone logs in with their credentials you may want to say
"You've successfully logged in".

I like this approach because it removes responsibility away from the
controller, and it makes things much easier to test (and to understand
IMO). And you have a very readable API,

Zach

On Jan 11, 2008 12:49 PM, Zach Dennis <zach.dennis at gmail.com> wrote:
> We pass the required items in as method arguments. In the spirit of
> sharing code and getting people to review code. Here is our current
> LoginManager:
>
> class LoginManager
>   include Injection
>   inject :invitation_manager
>
>   def login_from_cookie(cookies, session)
>     CookieLoginManager.new(
>       :cookies => cookies,
>       :session => session,
>       :invitation_manager => @invitation_manager
>     ).login
>   end
>
>   def login_from_session(session)
>     SessionLoginManager.new(
>      :session => session,
>      :invitation_manager => @invitation_manager
>     ).login
>   end
>
>   def login_with_credentials(options, session, cookies)
>     UserCredentialsLoginManager.new(
>       :options => options,
>       :session => session,
>       :cookies => cookies,
>       :invitation_manager => @invitation_manager
>     ).login
>   end
>
>   def login_from_password_reset(user, session)
>     PasswordResetLoginManager.new(
>       :user => user,
>       :session => session
>     ).login
>   end
>
>   def login_from_signup(user, session)
>     SignupLoginManager.new(
>       :user => user,
>       :session => session,
>       :invitation_manager => @invitation_manager
>     ).login
>   end
>
> end
>
>
> The reason we did this in the first place was that we needed to be
> able to add functionality (accepting invitations) to the login process
> and it seemed to get ugly without having it isolated in it's own
> object. We use additional login managers behind the scenes to have
> simple testable objects for each type of login we do.
>
> The "Injection" module just lets us pull out existing objects from a
> global app content and assign them as instance variables. That is how
> we are getting reference to invitation manager.
>
> Zach
>
>
> On Jan 11, 2008 12:45 PM, Ben Mabey <ben at benmabey.com> wrote:
> >
> > Zach Dennis wrote:
> > > On Jan 11, 2008 11:56 AM, David Chelimsky <dchelimsky at gmail.com> wrote:
> > >
> > >> On Jan 11, 2008 9:54 AM, Ben Mabey <ben at benmabey.com> wrote:
> > >>
> > >>> David Chelimsky wrote:
> > >>>
> > >>>> In TDD there is a rule of thumb that says don't stub a method in the
> > >>>> same class as the method you're testing. The risk is that as the real
> > >>>> implementation of by_input_sets!() changes over time, it has access to
> > >>>> internal state that could impact the behaviour of decompose!().
> > >>>>
> > >>>>
> > >>> So, stubbing a current_user method on a rails controller would be
> > >>> considered bad practice?
> > >>> I suppose stubbing the find on User would be just as easy but I have
> > >>> always just stubbed controller.current_user.
> > >>>
> > >> Rails is tricky. These rules are stem from situations in which you are
> > >> in complete control of the design. Clearly, Rails makes it easy to
> > >> work with if you follow its conventions, but the resulting design is
> > >> far from Object Oriented. This is not an inherently bad thing - don't
> > >> get me wrong. I use Rails and it's a delight in terms of development.
> > >> But it's a challenge in terms of this kind of testing.
> > >>
> > >> That said, the User class object is a different object than a user
> > >> instance, so I have no issue w/ stubbing find on it.
> > >>
> > >> As for controller.current_user, a purist TDD view would have you move
> > >> that behaviour elsewhere. I break the rule and just stub it directly.
> > >> This general advice I learned from Uncle Bob Martin: sometimes you
> > >> have to break the rules, but when you do you should do it consciously
> > >> and feel dirty about it ;)
> > >>
> > >
> > > On the current project we've quit moved all authentication into a
> > > LoginManager. This has worked out so nicely as we have simple methods
> > > for: login_from_cookie, login_from_session,
> > > login_from_user_credentials, etc.
> > >
> > > This cleans up a lot of the hairy code sprinkled throughout
> > > controllers and before filters which were  trying to do some form of
> > > authentication based on peeking at the sessions themselves or
> > > validating users.
> > >
> > >
> > Interesting, do you pass in the session in the constructor or how do you
> > get access to the session data?
> >
> > -Ben
> >
>
>
>
>
> --
> Zach Dennis
> http://www.continuousthinking.com
>



-- 
Zach Dennis
http://www.continuousthinking.com


More information about the rspec-users mailing list