Stubbing-Eigenschaften mit privaten Setzern für Tests

10

Wir haben das Objekt

public class MyObject{
    protected MyObject(){}

    public string Property1 {get;private set;}
    public string Property2 {get;private set;}
    public string Property3 {get;private set;}
    public string Property4 {get;private set;}
    public string Property5 {get;private set;}
    public string Property6 {get;private set;}
    public string Property7 {get;private set;}
    public string Property8 {get;private set;}
    public string Property9 {get;private set;}
    public string Property10 {get;private set;}
}

In unserem Produktionscode füllen wir dieses Objekt über Automapper. Es kann auf die Eigenschaften zugreifen und sie korrekt einstellen.

Wenn wir diese Klasse in einer zukünftigen Pipeline testen möchten, ist es nicht möglich, die Eigenschaften mit Dummy-Werten zu füllen (gegen die getestet werden soll).

Es stehen einige Optionen zur Verfügung.

  • Benutzerdefinierte Konstruktoren, um die für die Tests erforderlichen Parameter zu akzeptieren und die Eigenschaften festzulegen, sind derzeit 3 ​​Konstruktoren erforderlich. Dies ist nicht sauber, da die Konstruktoren keine Geschäftsfunktionalität bereitstellen.

  • Machen Sie die Eigenschaften virtuell, damit die Klasse gestoppt werden kann. Das Markieren der Eigenschaften als virtuell bietet jedoch keinen geschäftlichen Wert und verschmutzt meine Klasse.

  • Fügen Sie der Klasse einen Objekt-Builder hinzu, um das Objekt intern zu erstellen. Wieder kein geschäftlicher Mehrwert. Vielleicht etwas sauberer, aber immer noch viel nicht relevanter Code in den Domänenobjekten.

Anregungen, Ratschläge oder alternative Möglichkeiten hier?

JMan
quelle

Antworten:

8

Sie haben eine Reihe von Optionen.

  • Verwenden Sie benutzerdefinierte Konstruktoren, virtuelle Eigenschaften oder einen Objekt-Builder. Das Grundprinzip dahinter ist, dass ein Objekt für sich stehen und nicht von Magie wie dem Automapper abhängen sollte. Eine Klasse, die völlig nutzlos ist, wenn nicht etwas Magie vor sich geht, ist keine sehr gut durchdachte Klasse. "Business Value" ist nicht die einzige Determinante für ein gutes Design.

  • Beziehen Sie den Automapper in den Testprozess ein. Einige werden sagen, dass dies kein Unit-Test mehr ist. Es ist nicht wichtig. Unit-Tests sind nicht die einzige Art von Tests.

  • Implementieren Sie etwas, das die Funktionalität von Automapper speziell zum Testen bereitstellt. Sie können ganz einfach ein kleines Dienstprogramm schreiben, das mithilfe von Reflektion Ihr Objekt aus einem Wörterbuch mit Eigenschaftsnamen und -werten auffüllt.

Schauen Sie sich auch diese Frage und Antwort an: Möchten Sie lieber private Inhalte für Tests intern / öffentlich machen oder eine Art Hack wie PrivateObject verwenden?

Mike Nakis
quelle
3

Ich zögere nicht, Reflexion für solche Dinge in Tests zu verwenden.

Ich mag es nicht, Dinge zum Verspotten virtuell zu machen, da dies den Code aus dem falschen Grund ändert.

Ich kenne Automapper nicht, aber ich stimme @Mike zu, dass es eine gute Idee sein kann, ihn in die Tests aufzunehmen. Der Unterscheidungseinheitentest / Integrationstest ist imo nicht sehr interessant. Sicher, wenn die Testsuite groß und langsam wird, müssen Sie Dinge filtern und klassifizieren, um nur eine sinnvolle Teilmenge aller Tests mit der höchsten Frequenz auszuführen.

Beispiel-Hack mit Reflection und nameof () hat eine bessere Leistung, aber dann verlieren Sie Typen:

public static class TestExtensions
{
    public static void SetProperty<TSource, TProperty>(
        this TSource source,
        Expression<Func<TSource, TProperty>> prop,
        TProperty value)
    {
        var propertyInfo = (PropertyInfo)((MemberExpression)prop.Body).Member;
        propertyInfo.SetValue(source, value);
    }
}
Johan Larsson
quelle
0

Verwenden Sie zum Testen von Einheiten Verspottungsframeworks wie Microsoft Fakes, TypeMock und JustMock, die Unterstützung für das Verspotten privater Mitglieder bieten.

Bitte schauen Sie sich auch Smocks (verfügbare @ nuget-Pakete) an. Die Einschränkung von Smocks ist, dass sie keinen Zugang zu privaten Mitgliedern bieten. Es kann jedoch statische und nicht virtuelle Mitglieder verspotten. Es ist auch kostenlos erhältlich.

Eine andere einfachste Möglichkeit ist die Verwendung von PrivateObject / PrivateType.

Karthik V.
quelle