Implementing a protected parameterless constructor for unit testing
If I have a type with a big-old (lots of params) constructor, is it a vali开发者_开发问答d approach to implement a protected parameterless constructor simply for the purposes of creating a derived "Fake" type to use for stubbing in unit tests?
The alternative is to extract an interface, but this is not always desireable in a codebase you do not have full control over...
It's not ideal, but it is valid.
To quote a couple of people who know more about this than me, in The Art of Unit Testing, Roy Osherove talks about unit tests being like a user of the code, and as such providing access specifically for them is not necessarily a bad thing.
And in Working Effectively with Legacy Code, Michael Feathers discusses several such techniques, pointing out that making things protected for testing can be better than making them public, although it's not necessarily the best way to do things. (In fact I'd recommend you read that book if you are working with legacy code, as it sounds like you are).
I think it depends what sort of code it is - if it's a public API where people are likely to take protected access to mean it's designed to be overridden, it's probably a bad idea, but on a typical business app where it's pretty obviously not meant to be overridden, I don't think it's a problem. I certainly do it sometimes in this situation.
Since you essentially have to treat protected the same as public, the answer would be no from a strictly object-oriented point of view.
You could add a private parameterless constructor though and invoke it through reflection, if that's not too much hassle.
Could you not create a class which extends the class you want to test? That lets you use your own constructor without having to create an interface.
Modifying your code or API to facilitate unit testing is generally undesirable (see the "Should I unit test private methods" debate), so actually using a new class rather than modifying your existing one might be the way forward.
There is the argument that non-sealed types should always declare a protected parameterless constructor (where your others have parameters).
This allows flexibility for subclasses to instantiate the class in their own way, not forced to provide parameters to the base constructor.
Mocking frameworks are just such an example of a subclass that wants the freedom to be able to instantiate the class in its own way; the mock object doesn't care for setting property defaults or dependencies since it will mock the return values anyway.
One day, your own classes or library customers may have wildly different ideas about setting up the class, and you don't want a type that you cannot evolve months down the line because you're forced to push something that's no longer necessary into the base ctor.
There are rare cases when you absolutely need to force some initialization value, but it is rare - note that structs should not have parameterless ctors.
精彩评论