Would I first mock the object using
book_object = double("Book")
allow(book_object).to receive(:read_page).and_return(...)
That certainly works, but I have two suggestions:
- Use instance_double("Book") instead of double("Book"). The latter is
not a verifying double, which means it does nothing to warn you when the
interface of your test double and that of Book instances diverge.
- Since you don’t appear to care about the arguments, you can in-line
the stub as part of the test double definition:
book_object = instance_double("Book", read_page: page_value)
and then mock the class by
book = class_double("Book")
allow(book).to receive(:new).and_return(book_object)
Again, you can inline the new stub:
book = class_double("Book", new: book_object)
Actually, you could inline it all into one line:
book = class_double("Book", new: instance_double("Book", read_page: page_value))
That said, neither your snippet nor this one-line will work for the code
snippet you pasted, because your snippet directly references the Book
constant.
One solution is to change the code under test to accept an injectable
book_factory argument (which can have a default value of Book but in your
test you can pass the class double for it). This makes has all the benefits
of dependency injection (makes the dependency explicit in the method
signature, supports additional flexibility by allowing the caller to pass a
different book implementation, etc) while having all the downsides of
dependency injection (added code, an additional argument that is just there
to support testing, YAGNI, etc).
Another approach is to chain as_stubbed_const off your class_double:
class_double("Book", new: instance_double("Book", read_page:
page_value)).as_stubbed_const
This will cause the Book constant to be defined (or replaced) for the
duration of the example as your class double, so that any code that
references the Book constant will get your test double rather than the real
Book class and/or an “undefined constant” error.
A third approach is to define your Book class and stub the new method on
that directly…but it sounds like you are wanting to avoid defining it so
one of the first two approaches better fits the workflow you are aiming
for, I think.
HTH,
Myron
On Thu, Jun 25, 2015 at 3:21 AM, JSchlinker <[email protected]>
wrote:
> I am using rspec-mock for test-driven-development.
>
> I am starting implementing a single class and mocking/stubbing the other
> classes using rspec-mock. Mocking only objects of classes yet to be
> implemented works well. However when I try to mock a class method and
> instance methods for objects of the same class I am not sure how the
> preferred way to do this looks like.
>
> I have code that e.g. looks like this:
>
> new_book = Book.new
> content = new_book.read_page(5)
>
> I now want to mock out everything that has to do with the class "Book". In
> this example this would mean "Book.new" and "new_book.read_page"
>
> Would I first mock the object using
>
> book_object = double("Book")
> allow(book_object).to receive(:read_page).and_return(...)
>
> and then mock the class by
>
> book = class_double("Book")
> allow(book).to receive(:new).and_return(book_object)
>
>
> Is this the way to go?
>
> --
> 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 [email protected].
> To post to this group, send email to [email protected].
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/rspec/0690a743-805e-410a-ba9d-2bc2a2ea930e%40googlegroups.com
> <https://groups.google.com/d/msgid/rspec/0690a743-805e-410a-ba9d-2bc2a2ea930e%40googlegroups.com?utm_medium=email&utm_source=footer>
> .
> For more options, visit https://groups.google.com/d/optout.
>
--
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 [email protected].
To post to this group, send email to [email protected].
To view this discussion on the web visit
https://groups.google.com/d/msgid/rspec/CADUxQmuYwv8wrqbUkJX3nkJPzQX4JZN34ktxcXcgiHUx9p5koA%40mail.gmail.com.
For more options, visit https://groups.google.com/d/optout.