Very interesting article by Martin Fowler about the use of Mock Objects in unit testing and how they influence the style of testing.
Mocks Aren't Stubs
http://www.martinfowler.com/articles/mocksArentStubs.html
The article seems pretty "complete" in that I repeatedly thought about issues that he later covered and discussed, like the coupling to implementation that Interaction based testing brings, the need for integration tests etc.
Personally, I have only ever done State based testing for real and even though I knew of Mock Objects (Piers Cawley did a brief talk at YAPC::Eu Munic a couple of years ago) I've never really used the technique. I thought the biggest point was to provide an environment to the tested object so it could make it through the test without barfing (i.e. using the mocks as stubs), but from Fowler's article it seems providing TDD guidance is at least as important.
The Java mock object classes in the article seems very useful with an elegant interface for defining what the mock object should do and evaluating how it was called. From reading the docs of Test::MockObject it seems to be similarly capable, but with a different interface. It may be more suited to the Test::More way of doing things rather than the xUnit way with test classes.
Googling CPAN for examples didn't match that many documents, but at least there are a few examples of real-world use.
I think I'll give it a test-drive and see how it works out.
Mocks are generally divided up into static vs dynamic. Dynamic mocks can be implemented by something like Test::MockObject (or EasyMock in Java) -- generally you create a generic object, tell it what it should do and how it should respond, then put it in your framework.
Static mock objects have their place too. They're around in Perl, just not as explicitly as in Java. For instance, you have Apache::FakeRequest distributed with mod_perl, or the DBD::Mock module I wrote to fake a database driver. Creating static mock IO handles (files, sockets) should be a piece of cake and fairly useful for testing, although these are easily implemented with Test::MockObject as well.
FWIW, I gave a short presentation to the Pittsburgh Perlmongers a few months ago about this. (It looks ugly, sorry about that.)
Re:static vs dynamic
phillup on 2004-07-23T17:58:36
Thanks for the link, I found it very informative.
One small (hopefully constructive) criticism of this slide.
A while back I was having problems with a certain session module (not apache::session). During my troubleshooting I looked at the tests. Nowhere in any of the test did the author actually save and restore session data. Yet, the primary task of the module is to save some data... and give it back to you later.
So, while you certainly shouldn't have to test other people's modules... you should at least run a few basic tests to make sure the module is doing what you think it should.
On page 38 of Large Project Testing Andy Lester points out that you may have to do some testing because of other people's code.
Some of the time I think we get a false feeling of how good the code is because of all the passing tests... and we don't really look at the quality of the tests. I guess I'm saying that a little skepticism and verification are good things. (Trust but verify)
In the end, if you are using the module it is your problem, even if it isn't your code. So... I would tweak the one point just a bit.
Re:static vs dynamic
lachoy on 2004-07-23T18:17:58
I didn't mean to say that you should never test other people's code, just that you should avoid it if possible. Particularly if what you're asking the module to do is its entire purpose -- Apache::Session does nothing else except store and retrieve session data, so I think it's a reasonable assumption that it is doing its job. If it's not you have bigger problems, and you hopefully have better avenues to find these problems than running my unrelated test suite. (IIRC I made this point during the actual presentation, which just highlights one of the problems with seeing slides after the fact
:-) In a perfect world you'd test everything end-to-end, but I simply don't have that kind of time for an open-source project. If I were doing testing for a health monitoring product, yes I'd test all the libraries I use as well. And you're right that this is a useful distinction to make, thanks.