|
Boost Users : |
From: Kevin Wheatley (hxpro_at_[hidden])
Date: 2006-09-12 05:38:53
Scott Meyers wrote:
> EventLog::EventLog(std::ostream& logstream); // an ostream must be
> // specified
>
> I've slept soundly with this philosophy for many years, but lately I've
> noticed that this idea runs headlong into one of the ideas of
> testability: that classes should be easy to test in isolation. The
> above constructor requires that an ostream be set up before an EventLog
> can be tested, and this might (1) be a pain and (2) be irrelevant for
> whatever test I want to perform. In such cases, offering a default
> constructor in addition to the above would make the class potentially
> easier to test. (In the general case, there might be many parameters,
> and they might themselves be hard to instantiate for a test due to
> required parameters that their constructors require....)
The key here is that mock/stub objects in C++ are in some way a pain.
In your example, what are you going to test with your event log that
won't need to be validated by checking the logstream?
In my cases I've used regex matching on the logstream, even in my
constructor test case I verify that nothing is written to the stream,
so I always supply a fake ostream - usually a string based stream that
I can validate.
I know there was some degree of push back in the blog-o-sphere of over
use of this form of Inversion of control (see
http://www.martinfowler.com/articles/injection.html for some of the
alternatives)
> Another thing I've noticed is that some users prefer a more exploratory
> style of development: they want to get something to compile ASAP and
> then play around with it. In particular, they don't want to be bothered
> with having to look up a bunch of constructor parameters in some
> documentation and then find ways to instantiate the parameters, they
> just want to create the objects they want and then play around with
> them. My gut instinct is not to have much sympathy for this argument,
Personally I'd prefer the use of Null objects mostly because I'm
objecting to code like this:
value myclass:method()
{
if (member_variable == is_not_set)
return NULL_OF_SOME_FORM;
// do something with member_variable
}
slightly better might be:
value myclass:method2()
{
if (member_variable == is_not_set)
throw something;
// do something with member_variable
}
but even better is code that reads
value myclass:method3()
{
// do something with member_variable
}
It fits better with the idea of value objects and makes me more likely
to write code that has a stronger exception guarantee, but thats me :-)
> So I'm confused. Constructors that "really" initialize objects detect
> some kind of errors during compilation, but they make testing harder,
> are arguably contrary to exploratory programming, and seem to contradict
> the advice of the designers of the .NET API. Constructors that "sort
> of" initialize objects are more test-friendly (also more loosely
> coupled, BTW) and facilitate an exploratory programming style, but defer
> some kinds of error detection to runtime (as well as incur the runtime
> time/space costs of such detection and ensuing actions).
So I guess I'd add the fact that a constructor IMO should be used to
initialize an object into a well defined state including setup of the
object's invariant. Two phase construction runs the risk that you
might forget something.
My view is that objects with large number of parameters passed into
the constructor smells of a missing object/responsibility in the
design, even if its a data transfer object, my making such a class
your trying to direct the programmer to not forget something.
Testability isn't really effected by single phase construction. In my
experience it helps because all your setup code is in 'one line', not
spread about.
These are of course guidelines and not hard and fast rules.
Kevin
-- | Kevin Wheatley, Cinesite (Europe) Ltd | Nobody thinks this | | Senior Technology | My employer for certain | | And Network Systems Architect | Not even myself |
Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net