Schreiben von Komponententests für eine Klasse, die externe EXE startet

9

Ich habe eine C # -Klasse geschrieben, die verwendet wird, um eine Liste von EXE-Dateien zu starten (keine von mir - EXEs von Drittanbietern, die ich ausführen muss) und sie am Laufen zu halten (wird gelegentlich überprüft, ob sie noch ausgeführt werden, und sie starten, wenn nicht). .

Ich bin in der Lage, die grundlegende Logik des Hinzufügens, Entfernens usw. gut zu testen. Wie teste ich Unit, ob die eigentliche Arbeit, EXEs zu behalten, funktioniert?

Mein erster Gedanke ist, eine Dummy-EXE zu starten, die sich nach 1 Sekunde schließt, und diese dann zum Testen zu verwenden. Ist das außerhalb des Bereichs der Unit-Tests?

MattW
quelle

Antworten:

12

Mein erster Gedanke ist, eine Dummy-EXE zu starten, die sich nach 1 Sekunde schließt, und diese dann zum Testen zu verwenden. Ist das außerhalb des Bereichs der Unit-Tests?

Ist das ein guter Test? Sicher, also erschaffe es. Ist es "ein Unit Test" im wahrsten Sinne des Wortes? Ich glaube nicht, ich würde dies einen "Systemtest" oder ähnliches nennen, aber das macht den Test nicht weniger wertvoll.

Doc Brown
quelle
9

Verspotten Sie es auf einer höheren Ebene. Erstellen Sie eine Proxy-Klasse Process.Start(), fälschen Sie diese im Test aus und überprüfen Sie die Eingabe.

public interface IProcessProxy
{
     ProcessInfo Start(string application, string[] arguments);
}

public class ProcessProxy : IProcessProxy
{
    public ProcessInfo Start(string application, string[] arguments)
    {
        return Process.Start(application, arguments);
    }
}

// You could use a mocking framework for this, but for the purposes
// of this example ...
public class FakeProcessProxy : IProcessProxy
{
    private string _expectedApplication;
    private string[] _expectedArguments;
    private ProcessInfo response;

    public FakeProxy(string expectedApplication, string[] expectedArguments, ProcessInfo response)
    {
         _expectedApplication = expectedApplication;
         _expectedArguments = expectedArguments;
    }

    public ProcessInfo Start(string application, string[] arguments)
    {
         // compare input to expectations and throw exception if not matching
         return _response;
    }
}

// You can also use an IoC framework to inject your IProcessProxy, but I won't.
public class ClassUnderTest
{
    public ClassUnderTest(IProcessProxy proxy)
    {
        _proxy = proxy;
    }

    public ClassUnderTest() : this(new ProcessProxy())
    {
    }

    public void MethodUnderTest()
    {
        // Do stuff

        ProcessInfo process = _proxy.Start(@"C:\Program Files\App\App.exe", new[] { "arg1", "arg2" });
        process.WaitForExit();

        if (process.ExitCode == 0)
        {
            // Act on success
        }
        else
        {
            // Act on failure
        }
    }   
}

Verwenden Sie den Standardkonstruktor, wenn Sie ClassUnderTest im Anwendungscode verwenden müssen. Übergeben Sie in Ihren Tests einen FakeProcessProxy an den anderen Konstruktor, wobei Sie Ihre erwarteten Proxy-Start-Parameter und Ihr Testergebnis im Konstruktor der Fälschung verwenden.

pdr
quelle
4

Wenn Sie sich strikt an die Philosophie des Unittesting halten (Schwerpunkt auf Einheit ), sollten Sie keine Exe-Datei erstellen, sondern testen, ob Ihre Klasse die Schnittstellen zum korrekten Laichen und Überwachen dieses Prozesses aufruft. Schließlich möchten Sie Ihre Klasse testen, nicht die Bibliothek, die für die Prozessabwicklung verantwortlich ist.

Aber aus pragmatischer Sicht ist Ihr Ansatz in Ordnung, obwohl 1 Sekunde etwas lang zu sein scheint.

keppla
quelle
1

Ich habe etwas Ähnliches gemacht, aber nur angerufen ping localhost. Spart den Aufwand, ausführbare Dateien auf Ihrem Build-Server abzulegen

Ben
quelle