In regards to unit testing, I was taught that production code shouldn't have test-related code in it.
Well, I feel like I'm breaking that rule every time I try to unit test.
I have a class internal to my assembly, Xyzzy
. I want to dependency inject it into another class and then stub it so I can test that the other class in isolation, so I make an interface, IXyzzy
. Oops, now I have code in production that's really only there for test. Even worse, I've kind of gone against what interface is (describes what an implementer can do, not what it is). Xyzzy's public interface and IXyzzy are exactly the same and no one else (except the stubs) implements IXyzzy.
That seems like a bad thing to me.
I could create an abstract base class or make all the public methods I want to test on Xyzzy Overridable
/virtual
, but that feels wrong too since Xyzzy isn't designed for inheritance and from a YAGNI perspective, won't ever be inherited from.
Is creating single-implementer interfaces solely for the purpose of testing an anti-pattern? Are there better alternatives?
The mockery is one of the most popular anti pattern across developers, as it seems that everyone has had some experience mocking code to test. The first idea, Mocking is simple: avoid external code to focus on what you want to test.
Unit testing is a software development process in which the smallest testable parts of an application, called units, are individually and independently scrutinized for proper operation. This testing methodology is done during the development process by the software developers and sometimes QA staff.
When you have an interface, you can easily “hide” any implementation behind it, even a mock for a unit test. An important subject of unit testing is managing external dependencies. The tests should directly cover the unit while using fake replacements (mocks) for the dependencies.
In computer programming, unit testing is a software testing method by which individual units of source code—sets of one or more computer program modules together with associated control data, usage procedures, and operating procedures—are tested to determine whether they are fit for use.
Yes, it is an anti-pattern. A pattern would be "a solution to a common problem in a certain context". But in this case, what we have is a work-around, not a solution.
The problem in question is the need to isolate a unit to be tested from (some of) its dependencies, so that the implementation of those dependencies doesn't have to be considered when writing the unit tests. The general and true solution to this problem is called "mocking", where the test writer can specify whatever behavior is needed from the mocked dependencies.
In contrast, forcing the developer to create unnecessary separate interfaces, or declare methods as virtual
, is only a work-around for the technical inability to cleanly isolate a unit from others.
For .NET, there are several mocking tools that provide this isolation ability, namely TypeMock Isolator, JustMock, and MS Fakes. Other languages/platforms (including Java, Ruby, and Python) have their own tools of similar expressive power.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With