How to adjust base class tests to test derived classes using NUnit
One of the categories of hard to chase down bugs I often see in C#.NET code is caused by violation of the Liskov Substitution Priniciple. In this post, I'll show a quick way to adapt NUnit unit tests for a base class to also test a derived class.
Liskov Substitution Principle
In a nutshell, LSP requires that derived types when substituted for their base types should behave in exactly the same way.
The Problem
In modern applications, it is fairly common to see inheritance implementations that break the LSP rule. If the violation isn't caught and fixed, it is a bug waiting to happen. Eventually, some program code will perform an operation using an object of a type derived from the base class, relying upon it to behave as the base class does. When it does, things will break.
The Rectangle/Square Example of LSP Violation
In geometry, a square is just a special type of rectangle with width and height equal.
Naïvely, a developer may decide to represent this in code as a Square class inheriting from a Rectangle class.
The Solution
The original unit tests for Rectangle at some point create a Rectangle instance.
The first step is to move this instantion into a [SetUp]
method in your NUnit [TestFixture]
. The setup method runs before every individual test.
The next step is to refactor the test class to be generic; something similar to the following will work:
public class ViolatorTests<TShape> : AssertionHelper where TShape : IRectangle, new()
.
Next change the setup method to instantiate an instance of the generic type TShape
.
With these changes in place, you simply need to change your TestFixture
attribute to [TestFixture(typeof(Rectangle))]
. This gets you back to your original Rectangle tests.
Finally, to make the base class tests run against the derived type, simply add another TestFixture
attribute to the class – this will cause the NUnit framework to run the test suite against the new type specified.
Below is a complete example for the rectangle/square scenario. The test will fail when the derived type Square
is used, indicating that you have a violation of LSP and need to rethink how the two classes should be related
Conclusion
By slightly refactoring your NUnit base class unit tests to be generic, you can make them usable for testing derived classes without writing duplicate tests (remember: DRY – Don't Repeat Yourself). This will catch LSP violations early in development and prevent hard to pin down bugs.
No comments:
Post a Comment