Forum: RSpec message expectations without explicit receiver

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
Barun S. (Guest)
on 2009-04-10 22:45
(Received via mailing list)
A model I'm trying to spec looks something like this

class MyClass
  def methodA
    do some stuff
    methodB
  end

  def methodB
    do some stuff
  end
end

my spec looks something like this:

x = MyClass.new
x.should_receive(:methodB)
lambda{ x.methodA }

In the situation outlined above, the spec fails.  But, if I change the
definition of methodA to be as follows the spec passes (note the
addition of
"self" as the receiver):

def methodA
  do some stuff
  self.methodB
end


The code doesn't actually need for me to identify "self" as the receiver
on
order for it to work.  But rSpec seems to require this.  Is there an
alternative way to write the spec so that it passes in the original case
(where I call methodB without an explicit receiver)?
Matt W. (Guest)
on 2009-04-11 00:42
(Received via mailing list)
On 10 Apr 2009, at 19:43, Barun S. wrote:

>   end
> addition of "self" as the receiver):
> the original case (where I call methodB without an explicit receiver)?
You're going into some pretty messy territory here, trying to insert a
mocking layer between two methods of the same class. Since most people
who use RSpec wouldn't want to do this, you've found that's it not
possible. I also suspect it would be quite difficult to write the
mocking code, but that's a different issue.

I could write more about this, and I suspect others will, but for now
I would suggest that you listen to your test and try to test the
behaviour of the whole class, only mocking out collaborating objects.
This will ensure there's as little coupling as possible between the
tests and the code, making that code easier to change. Here are a
couple of things you could read up to see what I mean:

http://www.jmock.org/oopsla2004.pdf
http://www.patmaddox.com/blog/2008/10/27/testing-p...

Matt W.
http://beta.songkick.com
http://blog.mattwynne.net
Nigel T. (Guest)
on 2009-04-11 00:44
(Received via mailing list)
Hi Barun,
Here is my take on this...

Why are you mocking methods on the object under test? The aim of BDD is
to
specify the behaviour of the class. When you are mocking, the intention
is
to spec one object in isolation. When you define expectations between
objects you are specifying object interaction.

Mocking method on the object under test ties your spec to your
implementation. If you decided to implement 'methodA' in some other way
that
lead to the same behaviour, then your specs shuould still pass. In your
case
they would not.

Cheers
Nigel

2009/4/11 Barun S. <removed_email_address@domain.invalid>
Barun S. (Guest)
on 2009-04-11 01:32
(Received via mailing list)
Ok, well it seems that the answer to my direct question is that no,
there's
no way to test message expectations without an explicit receiver; thanks
for
the responses.

I suppose I should respond to the comments re: more general issue of
testing
strategy [hopefully this doesn't ignite too long of a thread]:

I completely agree that the goal should be to disconnect testing from
implementation as much as possible.  In general, this requires finding
the
simples set of N inputs to a method that cover all the basic behavior
you
want to test for, and making sure that the appropriate output is
generated
for all of those cases.

This may work for the majority of methods you encounter; but it's not
always
practical.  Sometimes a method is complex enough that the N inputs you
would
need to describe all behavior can be too large to be practical.  We want
to
test thoroughly and to test in a way that's easy to maintain.  Overall
it is
easier to maintain tests that don't rely at all on implementation, but
it is
also easier to maintain a smaller number of tests than a very large
number
of tests.  These two things have to be balanced.

So, I do agree with the general rule, but it doesn't apply in every
situation.  And, to be clear, this has nothing to do with testing
protected
methods, which of course shouldn't be done.  Here's an example to
illustrate
my point:

Suppose methodA does the following:
  * parse a data file uploaded by the user
  * reformat the parsed data to deal with a variety of different
allowable
configurations
  * perform calculations on the collected data

In the implementation, I might refactor the functionality into three
smaller
methods (one for each bullet), and just call those three smaller methods
from within methodA.  Those other methods will also be public (they
might
need to be called from elsewhere), and I test each of them separately.
So,
having tested all of the functionality described by those three bullets
separately, all I really care about in testing methodA is that it is
actually calling those three methods.  Otherwise, re-testing all that
functionality is not at all DRY.

Even if I wanted to re-test all of the functionality, it can be next to
impossible.  Suppose I write 20 tests to fully spec out each of the
three
methods called from within methodA (because there are 20 distinct sets
of
behaviors that describe all the possible behaviors of each of those
methods).  In this case, if I wanted to test methodA without referencing
any
internal logic at all, I might be required to write 20^3 = 8,000 tests
to
fully cover all of the logic described by the 60 tests used to cover the
three subroutines.
David C. (Guest)
on 2009-04-11 01:42
(Received via mailing list)
On Fri, Apr 10, 2009 at 3:43 PM, Barun S. <removed_email_address@domain.invalid> 
wrote:
>   end
> end
>
> my spec looks something like this:
>
> x = MyClass.new
> x.should_receive(:methodB)
> lambda{ x.methodA }

Why the lambda? Is it ever called? The following works as expected:

class Foo
  def bar
    baz
  end

  def baz
  end
end

describe "a message expectation on the same object" do
  it "works just fine" do
    foo = Foo.new
    foo.should_receive(:baz)
    foo.bar
  end
end

- David

>
> The code doesn't actually need for me to identify "self" as the receiver on
> order for it to work.  But rSpec seems to require this.  Is there an
> alternative way to write the spec so that it passes in the original case
> (where I call methodB without an explicit receiver)?

Something
David C. (Guest)
on 2009-04-11 01:54
(Received via mailing list)
On Fri, Apr 10, 2009 at 6:27 PM, Barun S. <removed_email_address@domain.invalid> 
wrote:
> want to test for, and making sure that the appropriate output is generated
> So, I do agree with the general rule, but it doesn't apply in every
> In the implementation, I might refactor the functionality into three smaller
> methods called from within methodA (because there are 20 distinct sets of
> behaviors that describe all the possible behaviors of each of those
> methods).  In this case, if I wanted to test methodA without referencing any
> internal logic at all, I might be required to write 20^3 = 8,000 tests to
> fully cover all of the logic described by the 60 tests used to cover the
> three subroutines.

I responded to your initial post - I think we're chasing a red herring
here because what you want to be able to do *should* work.

That said, the traditional view of what you're describing now is to
extract behaviour to separate objects, not just a separate methods,
and then use mock objects in the examples. That solves the explosion
of examples to cover edge cases without the risks associated with
modifying the object being specified.

Not to say this is law, nor that I never violate it myself. But pretty
much the only time I do so is when a framework I'm using pushes me to
do so. If the class being spec'd is a PORO, and all my code, I
generally follow this guideline.

HTH,
David
Ashley M. (Guest)
on 2009-04-11 01:57
(Received via mailing list)
On 10 Apr 2009, at 22:27, Barun S. wrote:
> situation.  And, to be clear, this has nothing to do with testing
> protected methods, which of course shouldn't be done.  Here's an
> example to illustrate my point:
>
> Suppose methodA does the following:
>   * parse a data file uploaded by the user
>   * reformat the parsed data to deal with a variety of different
> allowable configurations
>   * perform calculations on the collected data

Hi Barun

The situation you describe is a violation of the Single Responsibility
principle.  Your *class*, never mind your method, is doing too much.

> Even if I wanted to re-test all of the functionality, it can be next
> to impossible.  Suppose I write 20 tests to fully spec out each of
> the three methods called from within methodA (because there are 20
> distinct sets of behaviors that describe all the possible behaviors
> of each of those methods).  In this case, if I wanted to test
> methodA without referencing any internal logic at all, I might be
> required to write 20^3 = 8,000 tests to fully cover all of the logic
> described by the 60 tests used to cover the three subroutines.


What you need to do is figure out how you can isolate parts of the
algorithm and spec them as separate objects.  That way you can mock
out the other bits, and cut down the permutations you need to cover to
prove the app still works.

Excessive build-up of logic branches is something I struggled with for
a long time, and it still bit me recently.  But, in my experience,
it's always just a code/spec smell.  As soon as the specs get too
complex to understand, find a simpler way of expressing you problem.
This can be either by refactoring with standard OO techniques, or - if
that fails to reduce the complexity - fundamentally re-modelling the
problem.

HTH

Ashley

--
http://www.patchspace.co.uk/
http://www.linkedin.com/in/ashleymoran
http://aviewfromafar.net/
http://twitter.com/ashleymoran
David C. (Guest)
on 2009-04-11 02:01
(Received via mailing list)
On Fri, Apr 10, 2009 at 6:55 PM, Ashley M.
<removed_email_address@domain.invalid> wrote:
>> So, I do agree with the general rule, but it doesn't apply in every
> Hi Barun
>
> The situation you describe is a violation of the Single Responsibility
> principle.  Your *class*, never mind your method, is doing too much.

Agreed. FWIW.
Barun S. (Guest)
on 2009-04-11 02:17
(Received via mailing list)
Ah, it was a red herring indeed...  I was using the lambda because my
actual
test was like:

lambda {x.methodA}.should raise_error

The problem was that an error was being raised before I expected it to
be
raised, and before "methodB" was ever called.  I thought calling the
explicit "self" receiver made a difference only because I was generating
some random data for my tests that by chance didn't fail when I made
that
change (this hole in the test data is fixed now).

Re: the more general code design  --

In general the code does obey the Single Responsibility Principle, but
this
particular class I'm spec'ing right now doesn't do that so well.  I
suspect
you're right that it would be worthwhile to look at how to better split
responsibilities into new classes. The specs themselves are proving to
be
helpful in determining where and how things could be refactored.

Thanks (and sorry for the non-issue problem).
This topic is locked and can not be replied to.