[rspec-users] Mocking, changing method interfaces and integration tests
pergesu at gmail.com
Fri May 25 18:33:30 EDT 2007
On 5/25/07, David Chelimsky <dchelimsky at gmail.com> wrote:
> On 5/25/07, Pat Maddox <pergesu at gmail.com> wrote:
> > This is something I've kind of struggled with over the past few months
> > . And just yesterday I made the decision to move away from mocks
> > in most cases. That decision resulted from me changing a db column
> > name from 'user' to 'username', but one of my tests mocked a
> > #find_by_user method, so the test passed even though my code was
> > broken.
> > Just to note, I've got ~7k lines of Rails spec code that uses mocks,
> > and tens of thousands that don't. So I've used both approaches
> > extensively in multiple projects, and have formed the following ideas.
> > I think David has a really good point about mock usage being related
> > to customer/programmer test coverage. At this point, we don't have
> > any customer tests. I also don't like the idea of relying on
> > heavyweight browser-based tests. I want to be able to run rake and
> > know that my code works.
> > Over the past week, I've converted a number of my controller tests to
> > use the real implementations instead of using mocks. It was obvious
> > when I realized that in my controllers I'm concerned with state a lot
> > more than interaction - a request is made, some state changes, a
> > response is given. I want my tests to prove that those state changes
> > are actually being made. In this way, my controller specs act as
> > integration tests. I do a *tiny* bit of mocking in controller specs,
> > in cases where I can't verify state such as making some notification
> > request to another machine in the system.
> > I'm still using mocks quite a bit in my model specs, and I'm not quite
> > sure if I'll be cutting back or not. Just going to take it a day at a
> > time and try to remove any pain.
> > You've all surely read Martin Fowler's discussion about
> > interaction-based vs state-based testing. One of the points Dave
> > Astels always hammers on about BDD and interaction-based testing is
> > that it's not testing, it's a design tool. I've found that with mocks
> > I tend to arrive at a better design earlier on than I do without
> > mocks. I've also found that I can't change the design very easily.
> > Mocks are coupled to the design of the code, not the behavior. Aslak
> > says that state-based testing ain't BDD , but I disagree. If I
> > can't refactor - changing the design of the code without changing the
> > behavior - that doesn't seem very behavior-driven to me.
> > Mocks are nice as a design tool, but I've come to accept the fact that
> > creating a moderately good design early isn't as useful as having the
> > freedom to change my design later on. I'm just not good enough to
> > come up with the perfect design the first time around. My tests need
> > to give me the confidence to refactor. And I need to be able to run
> > those tests quickly from the command line rather than having to start
> > up a browser, even if it's automated. In that regard, mocks just
> > aren't for me, at least on my current project.
> One thing about TDD and the notion of a "design tool" - it's an
> ongoing process. If you want to end up w/ real models in your specs,
> you can still use mocks to figure out what they should do, then
> replace them w/ the real deal later. This is not nearly as expensive
> as it sounds, and lets you focus on one thing at a time.
I've considered that as well, and it's an attractive approach that I
plan to try soon.
> As for integration testing, what I've found w/ Rails is that if you do
> a couple of happy paths with rails built-in integration tests, you'll
> expose the refactoring problems that are raising such concern in this
> thread. For me, that's a win because you don't have to do the
> expensive in-browser stuff, everything's in Ruby, you still can use
> mocks to keep the isolation level stuff quick, and you run the slow
> integration tests before you commit.
I've yet to get major benefits from the integration tests. I realize
that it's nice to codify user stories, but so far it hasn't been nice
enough that I care very much. I'm okay with the "user adds an item to
car, user checks out" being split into separate controller tests. If
they both pass, I'm satisfied that my code works.
I don't think that integration tests are inherently bad, just that
they don't provide enough value (to me) over standard controller
tests, given the real downside of slowness.
> As for mocks tying you to implementation - I see a strong relationship
> to how well you follow "Tell, Don't Ask" and the value you get out of
> mocking. If you're doing a lot telling instead of asking, you have an
> implicitly more loosely coupled design. But if you want to make sure
> that the object being described does the telling, there's no better
> way to do that then with a mock in my view.
I absolutely agree. I didn't really get into this, but my model specs
use mocks quite a bit. And that's good, because if I use mocks then
it means I'm far more likely to write better OO code. After all, if
I'm doing a good job of "tell, don't ask" then there shouldn't be too
much state to verify.
So I guess I can summarize my first post as saying that I prefer to
use controller specs as very lightweight integration tests. In that
regard, I should be using real implementations where possible and
verifying the modified state of the system.
> 2 more cents.
> > Sorry for the length. pat.should be_less_verbose
> > Pat
> >  http://evang.eli.st/blog/2007/4/9/i-think-i-might-not-get-mocks
> >  http://www.martinfowler.com/articles/mocksArentStubs.html
> >  http://blog.aslakhellesoy.com/2006/12/11/the-bdd-cargo-cult
> > (for some reason it doesn't feel right to link to my blog and MF's
> > bliki together :)
> > _______________________________________________
> > rspec-users mailing list
> > rspec-users at rubyforge.org
> > http://rubyforge.org/mailman/listinfo/rspec-users
> rspec-users mailing list
> rspec-users at rubyforge.org
More information about the rspec-users