Verwenden von Shims zum Isolieren Ihrer App für Komponententests

Shim-Typen, eine der beiden Schlüsseltechnologien, die im Microsoft Fakes Framework verwendet werden, spielen eine entscheidende Rolle bei der Isolierung der Komponenten Ihrer App beim Testen. Sie funktionieren, indem Sie Aufrufe an bestimmte Methoden abfangen und umleiten, die Sie dann innerhalb des Tests an benutzerdefinierten Code weiterleiten können. Mit diesem Feature können Sie das Ergebnis dieser Methoden verwalten, damit Sie sicherstellen können, dass die Ergebnisse während jedes Aufrufs konsistent und vorhersehbar sind, unabhängig von externen Bedingungen. Diese Kontrollstufe optimiert den Testprozess und hilft dabei, zuverlässigere und genauere Ergebnisse zu erzielen.

Verwenden Sie Shims , wenn Sie eine Grenze zwischen Code und Assemblys erstellen müssen, die nicht Teil Ihrer Lösung sind. Wenn das Ziel darin besteht, Komponenten Ihrer Lösung voneinander zu isolieren, wird die Verwendung von Stubs empfohlen. Eine ausführliche Beschreibung zu Stubs finden Sie unter Verwenden von Stubs zum Isolieren von Teilen Ihrer Anwendung für Komponententests.

Dieser Artikel enthält eine schrittweise Anleitung für die Verwendung von Shim-Typen, um Aufrufe an bestimmte Methoden in Ihrem Komponententestcode umzuleiten.

Grundlegendes zu Typbeschränkungen mit Shims

Es gibt einige Einschränkungen beim Arbeiten mit Shims. Sie können nicht für alle Typen aus bestimmten Bibliotheken in der .NET Basisklasse verwendet werden, insbesondere:

  • mscorlib und System im .NET Framework
  • System.Runtime in .NET Core oder .NET 5+

Planen Sie beim Entwerfen Ihrer Teststrategie diese Einschränkung, um erfolgreiche und effektive Komponententests sicherzustellen.

Erstellen eines Shim

Angenommen, Ihre Komponente enthält Aufrufe der System.IO.File.ReadAllLines Methode:

// Code under test:
this.Records = System.IO.File.ReadAllLines(path);

Führen Sie die Schritte in den folgenden Verfahren aus, um die Komponente für Komponententests vorzubereiten.

Erstellen einer Klassenbibliothek

Erstellen Sie eine neue Lösung und ein erstes Projekt für die Klassenbibliothek.

  1. Erstellen Sie im Visual Studio Startfenster (File>Startfenster) ein Class Library Projekt, indem Sie die Vorlage für C# oder Visual Basic auswählen.

    Screenshot der Projektvorlage

    Screenshot der Projektvorlage

  2. Konfigurieren Sie das neue Projekt:

    • Legen Sie die Klassenbibliothek Project Name auf HexFileReader fest.
    • Legen Sie den Namen der Projektmappe auf ShimsTutorial fest.
    • Legen Sie das framework Target auf .NET Framework 4.8 fest.

    Wählen Sie "Erstellen" aus.

  3. Suchen Sie nach dem Öffnen des Projekts die Standarddatei Class1.cs in Projektmappen-Explorer, und löschen Sie die Datei.

  4. Fügen Sie eine Datei mit dem Namen hinzu HexFile.cs , und geben Sie die folgende Klassendefinition ein:

    // HexFile.cs
    public class HexFile
    {
        public string[] Records { get; private set; }
    
        public HexFile(string path)
        {
            this.Records = System.IO.File.ReadAllLines(path);
        }
    }
    

Hinzufügen eines Komponententestprojekts

Fügen Sie Ihrer Projektmappe ein weiteres Projekt für die Komponententests hinzu.

  1. Klicken Sie in Projektmappen-Explorer mit der rechten Maustaste auf die ShimsTutorial Lösung, und wählen Sie Add>Neue Project aus.

  2. Erstellen Sie im Startfenster eine Unit Test Project project, indem Sie die Vorlage auswählen.

    Screenshot der Projektvorlage Microsoft Unit Test für .NET Framework und C# in Visual Studio.

    Screenshot der Projektvorlage Microsoft Unit Test für .NET Framework und C# in Visual Studio 2022.

  3. Konfigurieren Sie das neue Projekt:

    • Legen Sie den Komponententest Project Name auf TestProject fest.
    • Legen Sie das framework Target auf .NET Framework 4.8 fest.

    Wählen Sie "Erstellen" aus.

Hinzufügen von Fakes Assembly

Fügen Sie einen Verweis auf das HexFileReader Projekt hinzu.

  1. Erweitern Sie in Projektmappen-Explorer den Knoten TestProject, klicken Sie mit der rechten Maustaste auf den Knoten Verweise, und wählen Sie Verweis hinzufügen aus.

    Screenshot, der zeigt, wie Sie in Visual Studio dem Unit-Test-Projekt einen Verweis auf die Klasse hinzufügen.

    Screenshot, der zeigt, wie Sie dem Komponententestprojekt in Visual Studio 2022 einen Verweis auf die Klasse hinzufügen.

    1. Wählen Sie im linken Bereich des Fensters "Verweis-Manager " den Abschnitt "Projekte " aus.

    2. Aktivieren Sie im mittleren Bereich das Kontrollkästchen für das HexFileReader Projekt, und wählen Sie "OK" aus.

  2. Fügen Sie die Fakes Assembly hinzu.

    1. Suchen Sie in Projektmappen-Explorer den Knoten, der die Assembly enthält:

      • Erweitern Sie bei einem älteren .NET Framework-Projekt (im Nicht-SDK-Stil) den Knoten des Unit-Test-Projekts, und erweitern Sie dann den Knoten References.

      • Für ein Projekt im SDK-Stil mit Ziel für .NET Framework, .NET Core oder .NET 5+ erweitern Sie den Knoten Dependencies, um unter Assemblies, Projects oder Packages die zu imitierende Assembly zu finden.

      • Wählen Sie in Visual Basic in der Symbolleiste Projektmappen-ExplorerShow All Files aus, um den Knoten References anzuzeigen.

    2. Wählen Sie die System-Assembly aus, die die Definition von System.IO.File.ReadAllLines enthält.

    3. Klicken Sie mit der rechten Maustaste auf den System Knoten, und wählen Sie "Fakes Assembly hinzufügen" aus.

      Screenshot, der zeigt, wie die Fakes-Assembly für das Projekt in Visual Studio hinzugefügt wird.

      Screenshot, der zeigt, wie die Fakes-Assembly für das Projekt in Visual Studio 2022 hinzugefügt wird.

    Der Buildprozess erzeugt Warnungen und Fehler für Typen, die für die Verwendung mit Shims nicht unterstützt werden.

    Nach Abschluss des Builds wird Projektmappen-Explorer aktualisiert, um einen Fakesknoten für das Komponententestprojekt anzuzeigen.

  3. Wählen Sie die Fakes\mscorlib.fakes Datei aus, und ersetzen Sie den XML-Code, um die nicht unterstützten Typen auszuschließen:

    <Fakes xmlns="http://schemas.microsoft.com/fakes/2011/" Diagnostic="true">
    <Assembly Name="mscorlib" Version="4.0.0.0"/>
    <StubGeneration>
         <Clear/>
    </StubGeneration>
    <ShimGeneration>
         <Clear/>
         <Add FullName="System.IO.File"/>
         <Remove FullName="System.IO.FileStreamAsyncResult"/>
         <Remove FullName="System.IO.FileSystemEnumerableFactory"/>
         <Remove FullName="System.IO.FileInfoResultHandler"/>
         <Remove FullName="System.IO.FileSystemInfoResultHandler"/>
         <Remove FullName="System.IO.FileStream+FileStreamReadWriteTask"/>
         <Remove FullName="System.IO.FileSystemEnumerableIterator"/>
    </ShimGeneration>
    </Fakes>
    

Erstellen eines Komponententests

Fügen Sie einen Komponententest für Ihr Projekt hinzu.

  1. Aktualisieren Sie die von der Projektvorlage bereitgestellte Standarddatei TestProject\UnitTest1.cs .

    Suchen Sie den folgenden Codeabschnitt in der Datei, und ersetzen Sie ihn durch den bereitgestellten Codeausschnitt:

    [TestMethod]
    public void TestMethod1()
    {
    }
    

    Ersetzungsausschnitt:

    [TestMethod]
    public void TestFileReadAllLine()
    {
       using (ShimsContext.Create())
       {
          // Arrange
          System.IO.Fakes.ShimFile.ReadAllLinesString = (s) => new string[] { "Hello", "World", "Shims" };
    
          // Act
          var target = new HexFile("this_file_doesnt_exist.txt");
    
          Assert.AreEqual(3, target.Records.Length);
       }
    }
    
  2. Um alle Fakes-Assemblies für den Unit-Test anzuzeigen, wählen Sie in der Menüleiste des Projektmappen-Explorer die Option Show All Files aus:

    Screenshot des Projektmappen-Explorers in Visual Studio 2022 mit allen Dateien, einschließlich der Fakes-Assemblys.

  3. Öffnen Sie den Test-Explorer , und führen Sie den Test aus.

Es ist wichtig, jeden Shim-Kontext ordnungsgemäß zu löschen. Rufen Sie als Faustregel die ShimsContext.Create Methode innerhalb einer using Anweisung auf, um das ordnungsgemäße Löschen der registrierten Shims sicherzustellen. Zum Beispiel könnten Sie einen Shim für eine Testmethode registrieren, der die DateTime.NowMethode durch einen Delegaten ersetzt, der immer den 1. Januar 2000 zurückgibt. Wenn Sie vergessen, den registrierten Shim in der Testmethode zu löschen, gibt der Rest der Testausführung immer den 1. Januar 2000 als DateTime.Now Wert zurück. Dieses Ergebnis kann überraschend und verwirrend sein.

Überprüfen von Benennungskonventionen für Shim-Klassen

Shim-Klassennamen verwenden das Fakes.Shim Präfix gefolgt vom ursprünglichen Typnamen. Parameternamen werden an den Methodennamen angefügt. (Sie müssen keinen Verweis auf System.Fakes hinzufügen.)

System.IO.File.ReadAllLines(path);

System.IO.Fakes.ShimFile.ReadAllLinesString = (path) => new string[] { "Hello", "World", "Shims" };

Verstehen, wie Shims funktionieren

Shims funktionieren, indem sie Umleitungen in die Codebasis der getesteten Anwendung einfügen. Bei jedem Aufruf der ursprünglichen Methode greift das Fakes-System ein und leitet den Aufruf um, sodass statt der ursprünglichen Methode Ihr benutzerdefinierter Shim-Code ausgeführt wird.

Es ist wichtig zu beachten, dass diese Umwege zur Laufzeit dynamisch erstellt und entfernt werden. Detours sollten immer während der Lebensdauer eines ShimsContext erstellt werden. Wenn der ShimsContext verworfen wird, werden alle darin erstellten aktiven Shims ebenfalls entfernt. Um dieses Design effizient zu verwalten, empfiehlt es sich, die Erstellung von Umwegen innerhalb einer using Aussage zu kapseln.

Erkunden von Shims für verschiedene Arten von Methoden

Shims unterstützen verschiedene Methodentypen.

Statische Methoden

Wenn Sie statische Methoden mit Shims versehen, sind die Eigenschaften, die die Shims enthalten, innerhalb eines Shimtyps enthalten. Diese Eigenschaften besitzen nur einen Setter, der verwendet wird, um einen Delegaten an die Zielmethode anzuhängen.

Beispiel: für eine Klasse, die mit einer statischen Methode MyClassaufgerufen wirdMyMethod:

//Code under test
public static class MyClass {
    public static int MyMethod() {
        ...
    }
}

Sie können einen Shim an MyMethod anhängen, sodass er ständig 5 zurückgibt:

// Unit test code
ShimMyClass.MyMethod = () => 5;

Instanzmethoden (für alle Instanzen)

Genau wie statische Methoden können Instanzmethoden auch für alle Instanzen geschwengt werden. Die Eigenschaften, die diese Shims beherbergen, befinden sich in einem geschachtelten Typ namens AllInstances, um Verwirrung zu vermeiden.

Für die Klasse MyClass mit einer Instanzmethode MyMethod:

// Code under test
public class MyClass {
    public int MyMethod() {
        ...
    }
}

Sie können an MyMethod einen Shim anhängen, sodass dieser unabhängig von der Instanz stets 5 zurückgibt:

// Unit test code
ShimMyClass.AllInstances.MyMethod = () => 5;

Der folgende Codeausschnitt zeigt die generierte Typstruktur von ShimMyClass:

// Fakes generated code
public class ShimMyClass : ShimBase<MyClass> {
   public static class AllInstances {
      public static Func<MyClass, int>MyMethod {
         set {
            ...
         }
      }
   }
}

In diesem Szenario übergibt Fakes die Laufzeitinstanz als erstes Argument an den Delegaten.

Instanzmethoden (einzelne Laufzeitinstanz)

Instanzenmethoden können auch mithilfe verschiedener Stellvertretungen abgesenkt werden, je nach Empfänger des Anrufs. Bei diesem Ansatz kann dieselbe Instanzmethode für jede Instanz des Typs unterschiedliche Verhaltensweisen aufweisen. Die Eigenschaften, die diese Shims enthalten, sind Instanzmethoden des Shim-Typs selbst. Jeder instanziierte Shimtyp ist mit einer unformatierten Instanz eines shimmed-Typs verknüpft.

Beispiel: Eine Klasse MyClass mit einer Instanzmethode MyMethod:

// Code under test
public class MyClass {
   public int MyMethod() {
      ...
   }
}

Sie können für MyMethod zwei Shim-Typen erstellen, sodass der erste stets 5 zurückgibt und der zweite stets 10 zurückgibt:

// Unit test code
var myClass1 = new ShimMyClass()
{
   MyMethod = () => 5
};
var myClass2 = new ShimMyClass { MyMethod = () => 10 };

Der folgende Codeausschnitt zeigt die generierte Typstruktur von ShimMyClass:

// Fakes generated code
public class ShimMyClass : ShimBase<MyClass> {
   public Func<int> MyMethod {
      set {
         ...
      }
   }
   public MyClass Instance {
      get {
         ...
      }
   }
}

Auf die tatsächliche Shimmed-Typinstanz kann über die Instance Eigenschaft zugegriffen werden:

// Unit test code
var shim = new ShimMyClass();
var instance = shim.Instance;

Der Shim-Typ enthält auch eine implizite Konvertierung in den shimmed-Typ, mit der Sie den Shim-Typ direkt verwenden können:

// Unit test code
var shim = new ShimMyClass();
MyClass instance = shim; // Implicit cast retrieves the runtime instance

Shim-Konstruktoren erkunden

Konstruktoren sind vom Shimming keine Ausnahme. Sie können so angepasst werden, dass Objekten, die künftig erstellt werden, Shim-Typen zugewiesen werden. Beispielsweise wird jeder Konstruktor innerhalb des Shim-Typs als statische Methode mit dem Namen Constructor repräsentiert.

Betrachten Sie eine Klasse MyClass mit einem Konstruktor, der eine ganze Zahl akzeptiert:

public class MyClass {
   public MyClass(int value) {
      this.Value = value;
   }
   ...
}

Ein Shimtyp für diesen Konstruktor kann so eingerichtet werden, dass unabhängig vom an den Konstruktor übergebenen Wert jede zukünftige Instanz -5 zurückgibt, wenn der Value Getter aufgerufen wird:

// Unit test code
ShimMyClass.ConstructorInt32 = (@this, value) => {
   var shim = new ShimMyClass(@this) {
      ValueGet = () => -5
   };
};

Jeder Shim-Typ macht zwei Typen von Konstruktoren verfügbar:

  • Wenn Sie eine neue Instanz benötigen, verwenden Sie den Standardkonstruktor.
  • Wenn Sie einen Konstruktor-Shim haben, verwenden Sie den Konstruktor, der eine geshimmte Instanz als Argument entgegennimmt.
// Unit test code
public ShimMyClass() { }
public ShimMyClass(MyClass instance) : base(instance) { }

Der folgende Code veranschaulicht den generierten Typ für das ShimMyClass:

// Fakes generated code
public class ShimMyClass : ShimBase<MyClass>
{
   public static Action<MyClass, int> ConstructorInt32 {
      set {
         ...
      }
   }

   public ShimMyClass() { }
   public ShimMyClass(MyClass instance) : base(instance) { }
   ...
}

Access-Basismitglieder

Sie können die Shim-Eigenschaften von Basismitgliedern erreichen, indem Sie einen Shim für den Basistyp erstellen. Geben Sie dann die untergeordnete Instanz in den Konstruktor der Basis-Shim-Klasse ein.

Betrachten Sie beispielsweise eine Klasse MyBase mit einer Instanzmethode MyMethod und einem Untertyp MyChild:

public abstract class MyBase {
   public int MyMethod() {
       ...
   }
}

public class MyChild : MyBase {
}

Ein Shim für MyBase kann eingerichtet werden, indem ein neuer ShimMyBase-Shim erstellt wird:

// unit test code
var child = new ShimMyChild();
new ShimMyBase(child) { MyMethod = () => 5 };

Beachten Sie, dass der untergeordnete Shim-Typ implizit in die untergeordnete Instanz konvertiert wird, wenn Sie den untergeordneten Shim als Parameter an den Basis-Shim-Konstruktor übergeben.

Die Struktur des generierten Typs für ShimMyChild und ShimMyBase ähnelt dem folgenden Code:

// Fakes generated code
public class ShimMyChild : ShimBase<MyChild> {
   public ShimMyChild() { }
   public ShimMyChild(Child child)
       : base(child) { }
}
public class ShimMyBase : ShimBase<MyBase> {
   public ShimMyBase(Base target) { }
   public Func<int> MyMethod
   { set { ... } }
}

Statische Konstruktoren

Shim-Typen stellen eine statische Methode StaticConstructor bereit, um den statischen Konstruktor eines Typs zu ersetzen. Da statische Konstruktoren nur einmal ausgeführt werden, müssen Sie sicherstellen, dass der Shim konfiguriert ist, bevor auf ein Element des Typs zugegriffen wird.

Finalizer

Finalizer werden in Fakes nicht unterstützt.

Private Methoden

Der Fakes-Codegenerator erstellt Shim-Eigenschaften für private Methoden, deren Signatur ausschließlich sichtbare Typen enthält, d. h., deren Parameter- und Rückgabetypen sichtbar sind.

Bindungsschnittstellen

Wenn ein shimmed-Typ eine Schnittstelle implementiert, gibt der Codegenerator eine Methode aus, mit der alle Elemente von dieser Schnittstelle gleichzeitig gebunden werden können.

Zum Beispiel eine Klasse MyClass, die IEnumerable<int> implementiert:

public class MyClass : IEnumerable<int> {
   public IEnumerator<int> GetEnumerator() {
       ...
   }
   ...
}

Sie können die Implementierungen von IEnumerable<int> "in" MyClass durch Aufrufen der Bind Methode shimieren:

// Unit test code
var shimMyClass = new ShimMyClass();
shimMyClass.Bind(new List<int> { 1, 2, 3 });

Die generierte Typstruktur ShimMyClass ähnelt dem folgenden Code:

// Fakes generated code
public class ShimMyClass : ShimBase<MyClass> {
   public ShimMyClass Bind(IEnumerable<int> target) {
       ...
   }
}

Ändern des Standardverhaltens

Jeder generierte Shim-Typ enthält eine Instanz der IShimBehavior Schnittstelle, auf die über die ShimBase<T>.InstanceBehavior Eigenschaft zugegriffen werden kann. Dieses Verhalten wird ausgelöst, wenn ein Client ein Instanzmitglied aufruft, das nicht explizit abgefangen wird.

Wenn kein bestimmtes Verhalten festgelegt ist, verwendet der Entwurf standardmäßig die von der statischen ShimBehaviors.Current Eigenschaft zurückgegebene Instanz, die in der Regel eine NotImplementedException Ausnahme auslöst.

Sie können dieses Verhalten jederzeit ändern, indem Sie die InstanceBehavior Eigenschaft für jede Shim-Instanz anpassen.

Sie können z. B. das Verhalten ändern, um entweder nichts zu tun oder den Standardwert des Rückgabetyps zurückzugeben: default(T)

// Unit test code
var shim = new ShimMyClass();

//Return default(T) or do nothing
shim.InstanceBehavior = ShimBehaviors.DefaultValue;

Sie können das Verhalten für alle shimmed-Instanzen, bei denen die InstanceBehavior Eigenschaft nicht explizit definiert ist, auch global ändern, indem Sie die statische ShimBehaviors.Current Eigenschaft festlegen:

// Unit test code
// Change default shim for all shim instances where the behavior isn't set
ShimBehaviors.Current = ShimBehaviors.DefaultValue;

Identifizieren von Interaktionen mit externen Abhängigkeiten

Um zu ermitteln, wann Ihr Code mit externen Systemen oder Abhängigkeiten interagiert (so genannte environment), können Sie Shims verwenden, um allen Membern eines Typs (einschließlich statischer Methoden) ein bestimmtes Verhalten zuzuweisen. Durch Festlegen des ShimBehaviors.NotImplemented-Verhaltens auf der statischen Eigenschaft Behavior des Shim-Typs löst jeder Zugriff auf einen Member dieses Typs, der nicht explizit mit einem Shim versehen ist, eine NotImplementedException aus. Dieses Ergebnis kann während des Tests als nützliches Signal dienen, das angibt, dass Ihr Code versucht, auf ein externes System oder eine Abhängigkeit zuzugreifen.

Hier ist ein Beispiel dafür, wie Sie diese Art von Shim in Ihrem Code für Komponententests einrichten:

// Unit test code
// Assign the NotImplementedException behavior to ShimMyClass
ShimMyClass.Behavior = ShimBehaviors.NotImplemented;

Der Einfachheit halber steht auch eine Kurzschreibweise zur Verfügung, um denselben Effekt zu erzielen:

// Shorthand to assign the NotImplementedException behavior to ShimMyClass
ShimMyClass.BehaveAsNotImplemented();

Ursprüngliche Methoden innerhalb von Shim-Methoden aufrufen

In einigen Szenarien müssen Sie möglicherweise die ursprüngliche Methode während der Ausführung der Shim-Methode ausführen. Sie können beispielsweise Text in das Dateisystem schreiben, nachdem Sie den an die Methode übergebenen Dateinamen überprüft haben.

Ein Ansatz für diese Situation besteht darin, einen Aufruf der ursprünglichen Methode mithilfe eines Delegaten und der Methode ShimsContext.ExecuteWithoutShims() zu kapseln:

// Unit test code
ShimFile.WriteAllTextStringString = (fileName, content) => {
  ShimsContext.ExecuteWithoutShims(() => {

     Console.WriteLine("enter");
     File.WriteAllText(fileName, content);
     Console.WriteLine("leave");
  });
};

Alternativ können Sie den Shim nullifizieren, die ursprüngliche Methode aufrufen und dann den Shim wiederherstellen:

// Unit test code
ShimsDelegates.Action<string, string> shim = null;

shim = (fileName, content) => {
   try {
      Console.WriteLine("enter");
      // Remove shim in order to call original method
      ShimFile.WriteAllTextStringString = null;
      File.WriteAllText(fileName, content);
   }
   finally
   {
      // Restore shim
      ShimFile.WriteAllTextStringString = shim;
      Console.WriteLine("leave");
   }
};

// Initialize the shim
ShimFile.WriteAllTextStringString = shim;

Nebenläufigkeit mithilfe von Shim-Typen behandeln

Shim-Typen funktionieren über alle Threads innerhalb der AppDomain und besitzen keine Threadaffinität. Diese Eigenschaft ist entscheidend, um zu berücksichtigen, wenn Sie beabsichtigen, einen Testläufer zu verwenden, der Parallelität unterstützt. Es ist wichtig zu beachten, dass Tests, die Shim-Typen verwenden, nicht parallel ausgeführt werden können, obwohl die Fakes-Laufzeit diese Einschränkung nicht erzwingt.

Verwenden Sie Shims mit System.Environment

Um die System.Environment Klasse zu shimieren, müssen Sie die mscorlib.fakes Datei ändern.

Suchen Sie das \<Assembly> Element, und fügen Sie nach der Elementdefinition den folgenden Inhalt hinzu:

<ShimGeneration>
   <Add FullName="System.Environment"/>
</ShimGeneration>

Nachdem Sie Änderungen vorgenommen und die Lösung neu erstellt haben, sind die Methoden und Eigenschaften in der System.Environment Klasse jetzt für shimming verfügbar.

Hier ist ein Beispiel dafür, wie Sie der GetCommandLineArgsGet Methode ein Verhalten zuweisen können:

System.Fakes.ShimEnvironment.GetCommandLineArgsGet = ...

Wenn Sie diese Änderungen vornehmen, können Sie steuern und testen, wie Ihr Code mit Systemumgebungsvariablen interagiert, was ein wesentliches Tool für umfassende Komponententests ist.