[rspec-devel] [ rspec-Feature Requests-5064 ] Let mock() take a class argument

noreply at rubyforge.org noreply at rubyforge.org
Wed Nov 29 19:15:07 EST 2006

Feature Requests item #5064, was opened at 2006-07-14 21:28
You can respond by visiting: 

Category: None
Group: None
Status: Open
Priority: 3
Submitted By: Aslak Hellesøy (aslak_hellesoy)
Assigned to: Nobody (None)
Summary: Let mock() take a class argument

Initial Comment:
I'd like to start my development by using:
  thing = mock("thing")

Once I have discovered thing's interface, I'd like to switch to:
  thing = mock(Thing)

The idea is that should_expect would fail as long as Thing doesn't implement the expected method.
This is a great way to go to the next step - implementing the Thing interface.


>Comment By: David Chelimsky (dchelimsky)
Date: 2006-11-30 00:15

There are a lot of different ideas expressed in this thread. The thing that would be the most simple and, in my view, the most useful, would be Aslak's initial request BUT instead of failing you'd get feedback. We wouldn't use this for integration at all. So, if you do this:

thing = mock('thing')

you get things as they are now. If you do this:

thing = mock(Thing)

you get things as they are now, w/ failure messages reading 'Thing'. Then, if you CHOOSE to, you can run the spec command w/ a switch that simply provides a report of methods that are being called on the mock Thing that Thing will not respond to.

This can be very helpful when doing a top-down style of development in which mocks are used to help you discover the interfaces of the collaborators. In a statically typed language like java, you get this benefit automatically because you have to add methods to a java interface as you discover them. This facility in rspec would give you that little extra edge.

The whole doubling as integration idea is probably silly.



Comment By: Pat Maddox (pergesu)
Date: 2006-11-29 23:27

I've been thinking about this a lot over the past couple days.  We use rspec and mocks to specify the behavior of and interaction between objects.  When we mock behavior, all we care about is the interface - concrete classes shouldn't matter at all.

The more I think about it the less I like it.  Things like integration mode test behavior of the system, rather than of the objects themselves, and I think that's something that should be separate from the standard specifications.  Whether that's something that should be a part of RSpec, I'm not sure...but I am certain that testing the system behavior should be separate from specifying object behavior and interactions.


Comment By: Nathan Sobo (nathansobo)
Date: 2006-11-29 22:22

It would be helpful to continue to allow the mock method to take an optional descriptive string argument after the class argument.

Also, the should_receive method could be extended with an optional modifier that would suppress warnings for messages not corresponding to methods in the mocked class, such as messages that are known to be handled by method_missing. It could look like...


or something.


Comment By: David Chelimsky (dchelimsky)
Date: 2006-10-12 11:25

I've been thinking about this a bit and I'd like to take it even further. The thing that bugs me about this idea is that I have to keep track of which mocks are using a name and which are using the Class.

What if we started creating an empty Thing class and wrote this:

thing = mock(Thing)

That would run if the class exists, but it not yet be defined in any detail.

Then we could run specs in varying modes. Normally, they would run as they do now, with the exception that the mock expectation would read "Mock <Thing> expected...." or something like that.

A second mode, invoked w/ a command line option, would be that it does the checking that you talk about to make sure that all the messages being mocked have corresponding methods on the real class.

A third mode would be something someone proposed on the email list - an integration mode. This would require some additional setup and I'm not sure what that looks like (perhaps an integration_setup block?), but the idea is that you could run all of the same specs using real objects instead of the mocks. You wouldn't have to write separate integration specs.

This is something Dan described about JBehave when he and I spoke at Agile 06. When you run JBehave, it tells you how many mocks are still being used. The idea there is that you should remove them over time - just use them to get you there, but use the real objects as they come to be. When there are no mocks in the run and all the specs pass, you're done!

The nice thing about having a CL option to run them this way is that you can monitor your progress towards "done", but you can also run the specs in isolation normally. This gives you the benefits of both worlds - isolation and integration. In fact the mock modes could be isolation (default), verification and integration. That has some nice symmetry to it.




You can respond by visiting: 

More information about the rspec-devel mailing list