views:

230

answers:

5

Say we have this hyper simple class hierchy:

public class SomeMath
{
    public int Add(int x, int y)
    {
        return x + y;
    }
}

public class MoreMath : SomeMath
{
    public int Subtract(int x, int y)
    {
        return x - y;
    }
}

Should I write tests for the Add method when I write tests for the MoreMath class? Or should I only care about that method when I am testing the SomeMath class? More generally: Should I test all methods of a class, or should I only test "new" methods?

I can kind of come up with some reasons for both sides. For example, when testing all methods you will end up testing the same thing more than once, which is not so good and can become tedious. But if you don't test all methods, a change in SomeMath might break usages of MoreMath? Which would kind of be a bad thing too. I suppose it probably depends a bit on the case too. Like if it extends a class I have control over or not. But anyways, I'm a total test newbie, so I am curious to know what people smarter than I think about this :-)

+5  A: 

Normally I wouldn't test behavior in the child class unless the child class changes the behavior from that expected in the parent class. If it is using the same behavior, there is no need to test it. If you are planning to make breaking changes to the parent class but the child class still needs the old behavior, then I would first create tests in the child class to define its required behavior, then I would make the changes in the parent tests and subsequent code changes. This follows the YAGNI principle -- you aren't going to need it -- and delays the implementation of the child tests until they actually have a purpose.

tvanfosson
Sounds like a good practice :)
Svish
I think this answer assumes that unit tests are only written in a TDD fashion. In my opinion, that is only half of the answer, but see my answer for a fuller examination.
Mark Seemann
+1  A: 

I'd only test the Add method of the SomeMath class. If MoreMath only inherits it and does absolutely nothing new, then writing tests for both would be pure duplicate code, nothing more. It's always good to be a little pragmatic with these things imho.

Razzie
+1  A: 

First of all, I think that there are at least two factors that may influence your decision to do one or the other:

  • What is the purpose of the inheritance?
  • What is the purpose of the test in question?

In TDD scenarios, I would tend to write a single test case for MoreMath that verifies that it derives from SomeMath, and then consider all of the members inherited from SomeMath to be covered.

However, that implies that, from a design perspective, it is an important design aspect that MoreMath derives from SomeMath. This would definitely be the case if you use SomeMath in a polymorphic way. However, it wouldn't be the case if you simply use inheritetance for reuse (not recommended, though).

In the latter case (inheritance is used for reuse), there is no conceptual connection between the parent and child classes, and you may be tempted to break the inheritance in the future. In such cases, having a test that verifies that the parent is correct is a poor safeguard.

From a Quality Assurance (QA) standpoint, each and every member of each and every class should be tested rigorously. This means that you should repeat the test code for each child class even if the test code would be the same, because you need to verify that no virtual method was overridden in an unexpected way. However, to stay DRY you can write them as Parameterized Tests, or perhaps use a tool such as Pex.

Personally, I rarely get to the QA phase. Usually, the test suite created during TDD is an adequate safety net... but that all depends on the type of software you build.

Mark Seemann
Made this the answer since it was covering more angles :)
Svish
A: 

I would make my test class for MoreMath inherit from the test class for SomeMath, thus inheriting all of the tests of that class. This means I only have to write additional tests for the new features, but all the subclass' features are fully tested.

Matt Howells
+1  A: 

At my current place we came across a similar problem where we wanted to develop to interfaces but ensure that each implementation of the interface behaved correctly (e.g. different data layers should behave the same regardless of the implementation of that layer). The way we solved it (with NUnit) was to have an inheritance structure within the unit tests:

public interface ICalculator
{
  public int Add(int a, int b)
}

public class Calculator : ICalculator
{
  public int Add(int a, int b) { return a + b; }
}

public class TestCalculatorInterface
{
   public abstract SomeMath GetObjectToTest();

   [Test]
   public void TestAdd()
   {
       var someMath = GetObjectToTest();
       ...
   }
}    

[TestFixture]
public class TestCalculator: TestCalculatorInterface
{
   public virtual Calculator GetObjectToTest() { return new Calculator(); }
}

We would not have the [TestFixture] attribute on the base interface test but have the [Test] attribute on all of the test methods. The TestCalculator class is the [TestFixture] but inherits all of the tests from the base class which leaves the sub-class responsible solely for providing the object to test for that interface.

I would adopt a similar pattern for your case, so the tests are run against all of the classes but are only written once.

Ian Johnson
I've actually done something similar myself once :)
Svish