spec isolation when using 3rd party gems

15 views
Skip to first unread message

Andy

unread,
Jun 3, 2016, 11:40:41 AM6/3/16
to rspec
Hi,

I've been trying out rspec recently and I've also been trying to test in isolation more but I'm unsure how to approach specs for code that leverages 3rd parties.

Take this over simplified example:

class UserAuthenticator
 
def initialize(user)
   
@user = user
 
end

 
def authenticate_by_password(clear_password)
   
@user if BCrypt::Password.new(@user.hashed_password) == clear_password
 
end
end

In the test you could use a double for the user like this (I'm assuming this is the correct thing to do)

it 'returns a user if password is correct' do
  user
= double('User', hashed_password:"precomputed hash of 'pass'")
  expect
(UserAuthenticator.new(user).authenticate_by_password('pass')).to eql(user)
end

Would you leave it at that in this case? Or should Bcrypt be stubbed/mocked as well? Or should the password check using BCrypt be in it's own class/method (PasswordChecker)?

I guess I'm really interested at what point you would draw the line when it comes to isolating specs because it seems like trying to be a purist and isolate all external classes/methods leads to diminishing returns at some point.

Thanks.

Myron Marston

unread,
Jun 3, 2016, 11:48:19 AM6/3/16
to rs...@googlegroups.com
I would not use a test double for BCrypt in this case.  Generally we recommend only mocking interfaces you own, and you don't own the BCrypt interface.  In addition, AFAIK, the BCrypt provides a pure, side-effect-free and I/O-free interface, so I don't see how using a test double benefits you -- in this situation it looks like it just tightly couples your test to the BCrypt interface (making your test more brittle) and makes your test less realistic (providing no confidence it'll work w/o the test double).

However, if you wanted to provide an abstraction over BCrypt (e.g. to support swapping out hashing implementations in a single spot), it would make sense to use a test double in place of your own abstraction.

For the user, I would not necessarily use a test double unless `User` was a heavy dependency.  If it's just a light-weight struct or similar object, I'd just use the real thing.  If you do use the test double, we recommend you use `instance_double("User")` so as to get interface verification.

HTH,
Myron

--
You received this message because you are subscribed to the Google Groups "rspec" group.
To unsubscribe from this group and stop receiving emails from it, send an email to rspec+un...@googlegroups.com.
To post to this group, send email to rs...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/rspec/79d4a610-f034-4c27-b018-84c8a6bbf619%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Andy

unread,
Jun 3, 2016, 12:30:40 PM6/3/16
to rspec
Thanks for the response, it certainly clarifies a few things for me.
Reply all
Reply to author
Forward
0 new messages