通用类/方法的单元测试方法

时间:2010-05-12 11:02:23

标签: c# .net unit-testing generics

什么是推荐的方法来掩盖泛型类/方法的单元测试?

例如(参考下面的示例代码)。是否有2到3次测试来覆盖使用几种不同类型的TKey,TNode类测试方法?或者只是一个班级?

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) {
    .
    .
    .

5 个答案:

答案 0 :(得分:3)

我通常创建一个DummyClass用于测试目的,作为泛型参数传递(在您的情况下,您应该创建3个类),然后我测试类(TopologyBase)一次。

使用不同的泛型类型进行测试没有意义,因为泛型类型不应该破坏ToopologyBase类。

答案 1 :(得分:2)

这可能真的取决于你的代码,但至少要考虑两件事:

  • 私有/公共:如果您的实现使用或者有一天可能会使用反射或DLR(直接或通过C#中的dynamic关键字)进行某些操作,则应使用至少一种从实现程序集中看不到的类型进行测试。
  • ValueType / ReferenceType:例如,在某些情况下可能需要测试它们之间的差异
    • 对值类型(如ToString或Equals)调用Object方法总是正确的,但不能使用引用,因为它们可以为null。
    • 如果你正在进行性能测试,那么传递价值类型可能会产生影响,特别是如果它们很大(不应该在指南和现实之间发生,有时会有一个小的差距......)

答案 2 :(得分:1)

您可以使用模拟框架来验证您的类与泛型类型之间的预期交互。我为此使用了Rhino Mocks

答案 3 :(得分:1)

要对打开的生产类型进行单元测试,请创建一个从开放类型派生的测试代码类型 - 然后测试该类型。

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

在TestingTopologyBase类中,提供任何抽象方法或其他任何必需的基本实现。

这些测试[ProductionType]实现通常是您的单元测试代码的绝佳位置,可以感知测试中的泛型类型实际上在做什么。例如,您可以存储以后可供单元测试代码使用的信息,以检查测试期间发生的情况。

然后在您的单元测试方法中,创建TestingTopologyBase类的实例。这样,您可以从与其派生的任何生产类型中隔离测试泛型类型。

示例:

[TestClass]
public class TopologyBaseFixture {

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

答案 4 :(得分:0)

很大程度上取决于您的通用约束。如果一个或多个类型参数需要接口或基类约束,则现在依赖于接口契约。由于类的逻辑可能部分取决于实现接口的类的行为,因此您可能需要以各种方式模拟接口以执行所有逻辑路径。例如,如果你有T: IEquatable<T>,你需要使用一个具有有意义的相等行为的类型,比如int。