On 10/4/07, Nathan S. [email protected] wrote:
How would I go about writing specs for a lib, particularly one with
all protected and private methods. I’m trying to spec the
AuthenticatedSystem library from the rails restful_authentication
plugin:
Parked at Loopia
I think there are a few ways you can handle this. One would be to
create a class that includes that module and add public methods to
that class that access the protected ones:
class ExampleController
include AuthenticatedSystem
def has_logged_in_user?
logged_in?
end
end
controller.should_not have_logged_in_user
log_in #waving hands…
controller.should have_logged_in_user
Other possibilities would be to use instance_eval or make the methods
public from the example using send(:public, :logged_in?). I to avoid
that sort of thing when I’m developing code spec-first, but in the
case of back-filling specs on existing code I don’t mind using brute
force like that. It’s brittle, and in the end I might want to change
the design, but not until I’ve got it fairly well covered so I can
refactor in peace.
Also, when you’re mocking objects, a side-effect is helping you
define the api of the object.
Actually, I think that’s the whole point of mock objects and not a
side effect at all. If anything, the side-effect is isolation 
Is there a way to get all the
behaviors that have been mocked for a class and its objects? Is
there a way to automagically compare the output against what is
actually defined?
Mocha allows you to do this using responds_like:
account = mock(‘Account’).responds_like(Account)
account.expects(:withdraw)
If account does not respond_to?(:withdraw), then you get a failure.
Personally, I never use this. In practice, it means that every time I
say
object_i_am_NOT_defining_right_now.expects(:method_that_does_not_exist_yet)
I have to stop what I’m working on and add this method to the real
object. In the best case scenario, I’m disciplined about it and I
start writing specs for the new behaviour - completely losing the
context I was just in. In the less-than-best-case scenario, I’m not as
disciplined and I just add an empty method declaration in order to
quiet the noise. Neither case is desirable for me.
We’ve batted the idea of adding support for something like this to
rspec’s mock framework, but with a command line switch to turn it on
(default behaviour would be that it stays quiet). There’s an open RFE
for this in the tracker. I’m just not sure that it’s worth the trouble
when you consider the implications of behaviour getting added at
runtime and the like.
FWIW,
David