views:

88

answers:

5

Hi,

What's the recommended way to cover off unit testing of generic classes/methods?

For example (referring to my example code below). Would it be a case of have 2 or 3 times the tests to cover testing the methods with a few different types of TKey, TNode classes? Or is just one class enough?

public class TopologyBase<TKey, TNode, TRelationship> 
    where TNode : NodeBase<TKey>, new() 
    where TRelationship : RelationshipBase<TKey>, new()

{
    // Properties
    public Dictionary<TKey, NodeBase<TKey>> Nodes { get; private set; }
    public List<RelationshipBase<TKey>> Relationships { get; private set; }

    // Constructors
    protected TopologyBase()
    {
        Nodes = new Dictionary<TKey, NodeBase<TKey>>();
        Relationships = new List<RelationshipBase<TKey>>();
    }

    // Methods
    public TNode CreateNode(TKey key)
    {
        var node = new TNode {Key = key};
        Nodes.Add(node.Key, node);
        return node;
    }

    public void CreateRelationship(NodeBase<TKey> parent, NodeBase<TKey> child) {
    .
    .
    .
A: 

I usually create a DummyClass for test purpose to pass as a generic argument (in your case you should create 3 class) and the I test the class (TopologyBase) once.

Testing with different generic types doesn't make sense, since the generic type should not break the ToopologyBase class.

ema
So instead of creating a generic class of say Integer, you would create a new class specifically used for testing the generic class. Would you add any functionality into the new class?
Casey
Exactly. Nope the new class should be a Dummy that does nothing.
ema
A: 

You could use a mocking framework to verify expected interaction between the your class and the generic type. I use Rhino Mocks for this.

Christopherous 5000
+1  A: 

To unit test an open production type, create a test code type that derives from the open type - then test that type.

public class TestingTopologyBase : TopologyBase<KeyType, NodeType, RelationshipType> ...

In the TestingTopologyBase class, provide a base implementation of any abstract methods or anything else that is mandatory.

These Testing[ProductionType] implementations are often excellent places for your unit test code to sense what the generic type under test is actually doing. FOr instance, you can store away information that can later be used by your unit test code to inspect what went on during the test.

Then in your unit test methods, create instances of the TestingTopologyBase class. This way, you test the generic type in isolation from any production types that derive from it.

Example:

[TestClass]
public class TopologyBaseFixture {

    [TestMethod]
    public void SomeTestMethod() {
       var foo = new TestingTopologyBase(...);
       ...test foo here
Mahol25
A: 

It could really depends on your code but there are at least two things to think about :

  • Private / Public : If your implementation use or may someday use reflection or the DLR (directly or via the dynamic keyword in C#) for some operations you should test with at least one type that isn't visible from the implementing assembly.
  • ValueType / ReferenceType : The difference between them could need to be tested in some cases for example
    • Calling Object method on value types, like ToString or Equals is always correct, but not with references as they can be null.
    • If you are doing performance testing there could be consequences to passing around value types, especially if they are big (Shouldn't happens but between guidelines and reality sometimes there is a small gap...)
VirtualBlackFox
A: 

A lot depends on your generic constraints. If one or more of type parameters requires an interface or base class constraint, there is now a dependency on the interface contract. Since the logic of your class may partially depend on the behavior of the class implementing the interface, you may need to mock the interface in various ways to exercise all of your logical pathways. For instance, if you have T: IEquatable<T>, you'll need to use a type with meaningful equality behavior, like an int.

Dan Bryant