12 Stimmen

Unit-Test-Ansatz für generische Klassen/Methoden

Was ist der empfohlene Weg zur Abdeckung von Unit-Tests von generischen Klassen/Methoden?

Zum Beispiel (unter Bezugnahme auf meinen Beispielcode unten). Wäre es ein Fall von haben 2 oder 3 mal die Tests zu decken, die Methoden mit ein paar verschiedene Arten von TKey, TNode Klassen testen? Oder ist eine einzige Klasse ausreichend?

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

5voto

ema Punkte 5377

Ich erstelle in der Regel eine DummyClass zu Testzwecken, die ich als generisches Argument übergebe (in Ihrem Fall sollten Sie 3 Klassen erstellen) und teste die Klasse (TopologyBase) einmal.

Das Testen mit verschiedenen generischen Typen macht keinen Sinn, da der generische Typ die ToopologyBase-Klasse nicht zerstören sollte.

2voto

Julien Roncaglia Punkte 16839

Es könnte wirklich von Ihrem Code abhängen, aber es gibt mindestens zwei Dinge zu bedenken:

  • Private / Public : Wenn Ihre Implementierung Reflection oder DLR (direkt oder über das dynamische Schlüsselwort in C#) für einige Operationen verwendet oder verwenden könnte, sollten Sie mit mindestens einem Typ testen, der in der implementierenden Assembly nicht sichtbar ist.
  • WertTyp / ReferenzTyp : Der Unterschied zwischen ihnen könnte in einigen Fällen getestet werden müssen, zum Beispiel
    • Der Aufruf der Object-Methode bei Werttypen wie ToString oder Equals ist immer korrekt, aber nicht bei Referenzen, da diese null sein können.
    • Wenn Sie Leistungstests durchführen, könnte die Weitergabe von Werttypen Konsequenzen haben, insbesondere wenn sie groß sind (sollte nicht passieren, aber zwischen Richtlinien und Realität klafft manchmal eine kleine Lücke...)

1voto

Christoph Punkte 4033

Sie könnten ein Mocking-Framework verwenden, um die erwartete Interaktion zwischen Ihrer Klasse und dem generischen Typ zu überprüfen. Ich verwende Nashorn-Spötter für diese.

1voto

Mahol25 Punkte 3051

Um einen offenen Produktionstyp zu testen, erstellen Sie einen Testcodetyp, der von dem offenen Typ abgeleitet ist, und testen dann diesen Typ.

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

Stellen Sie in der Klasse TestingTopologyBase eine Basisimplementierung aller abstrakten Methoden oder sonstiger obligatorischer Methoden bereit.

Diese Testing[ProductionType]-Implementierungen sind oft ausgezeichnete Orte für Ihren Unit-Test-Code, um zu erkennen, was der zu testende generische Typ tatsächlich tut. So können Sie beispielsweise Informationen speichern, die später von Ihrem Unit-Test-Code verwendet werden können, um zu überprüfen, was während des Tests vor sich ging.

Erstellen Sie dann in Ihren Unit-Test-Methoden Instanzen der Klasse TestingTopologyBase. Auf diese Weise testen Sie den generischen Typ isoliert von allen Produktionstypen, die von ihm abgeleitet sind.

Exemple :

[TestClass]
public class TopologyBaseFixture {

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

0voto

Dan Bryant Punkte 27022

Vieles hängt von den allgemeinen Bedingungen ab, denen Sie unterliegen. Wenn einer oder mehrere der Typparameter eine Schnittstellen- oder Basisklassenbeschränkung erfordern, besteht nun eine Abhängigkeit vom Schnittstellenvertrag. Da die Logik Ihrer Klasse teilweise vom Verhalten der Klasse abhängt, die die Schnittstelle implementiert, müssen Sie die Schnittstelle möglicherweise auf verschiedene Weise nachbilden, um alle logischen Pfade zu nutzen. Zum Beispiel, wenn Sie T: IEquatable<T> müssen Sie einen Typ mit sinnvollem Gleichheitsverhalten verwenden, z. B. einen int.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X