following on from this question (Developing to an interface with TDD), I'm still having some issues.
I test-drove two classes into existence, both of which ended up shared some identical functionality. I refactored a common base class into existence, and all the tests still passed. So far, so tdd-tastic.
I needed a third class to implement the base class, so copied some tests into a new fixture and made each one compile and go green in turn, until I had a fully-functional third class. This approach can be debated, because if I didn't copy one test across correctly, or didn't change one successfully to support the new class, I'd be in trouble, but that's not the main problem.
The problem I have now is that I want to add functionality to the base class. It can't be instantiated on its own, so it will have to be through one of the leaf classes. However if I forget to copy the tests across to the other classes, I'll have unsupported functionality. It doesn't seem a very software-engineer-y way of doing things, and I wanted to know where I was going wrong.
Is this a problem with my design? Should I lay my tests out in a different way? Or am I worrying about nothing?
Thanks in advance.
One approach you could take is to organize your test units so you can re-use test code. This way, you don't have to copy/paste stuff around (copy/paste, even when it's for tests, is usually not something you want to do).
Or (what I do), you could just test one of your subclasses. I know, I know, it means that if you decide that one of your "partially covered" subclasses has to use another base class, or if that behavior you tested end up "bubbling up" to subclasses, you will have uncovered code.
However, this is the kind of things that seldom happen. Usually, when you refactor, you push down code to superclasses (to eliminate code duplication). When you do that kind of refactoring, you don't lose any coverage on the account of having only one of your subclasses tested for its superclass' behavior.
Therefore, I'm of the opinion that it's generally OK to test just one of your subclass in order to test a superclass' behavior.
Even though you can't create an instance of your base class directly, you can still unit test it by deriving a test-specific subclass that can be tested.
Assume that you have an abstract class called MyBase. Obviously, you can't create an instance of MyBase directly, but in your unit test project, you can create a test-specific specialization of MyBase called TestableBase or something else.
So let's assume that you want to test something like this:
And you want to test that DoStuffCore was correctly invoked by DoStuff, you can create something like this:
This would allow you to create a new instance of Spy and call its DoStuff method and then subsequently verify that the CoreInvoked property is true.