Écriture de tests unitaires pour une classe qui démarre un EXE externe

9

J'ai écrit une classe C # qui est utilisée pour démarrer une liste d'EXE (pas l'un des miens - EXE tiers que je dois exécuter) et les garder en cours d'exécution (vérifiera occasionnellement pour s'assurer qu'elle est toujours en cours d'exécution et les démarrera sinon) .

Je peux tester la logique de base de l'ajout, de la suppression, etc. Comment puis-je tester individuellement que le travail réel de conservation des EXE fonctionnera?

Ma première pensée est de démarrer un EXE factice qui se ferme après 1 seconde, puis de l'utiliser pour tester. Est-ce hors du domaine des tests unitaires?

MattW
la source

Réponses:

12

Ma première pensée est de démarrer un EXE factice qui se ferme après 1 seconde, puis de l'utiliser pour tester. Est-ce hors du domaine des tests unitaires?

Est-ce un bon test? Bien sûr, alors créez-le. S'agit-il d'un "test unitaire" au vrai sens du terme? Je ne pense pas, j'appellerais cela un "test système" ou quelque chose comme ça, mais cela ne rend pas le test moins valable.

Doc Brown
la source
9

Se moquer de lui à un niveau plus élevé que cela. Créez une classe proxy autour Process.Start(), simulez cela dans le test et vérifiez l'entrée.

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
        }
    }   
}

Partout où vous devez consommer ClassUnderTest dans le code d'application, utilisez le constructeur par défaut. Dans vos tests, passez un FakeProcessProxy à l'autre constructeur, en utilisant vos paramètres de démarrage de proxy attendus et votre résultat de test dans le constructeur du faux.

pdr
la source
4

Lorsque vous suivez strictement la philosophie de l’unittesting (accent mis sur l’ unité ), vous ne devez pas créer un fichier Exe, mais plutôt tester si votre classe appelle correctement les interfaces pour la génération et la surveillance de ce processus. Après tout, vous voulez tester votre classe, pas la bibliothèque responsable de la gestion des processus.

Mais d'un point de vue pragmatique, votre approche est bonne, même si 1 seconde semble être un peu longue.

keppla
la source
1

J'ai fait quelque chose de similaire, mais j'ai juste appelé ping localhost. Économise les tracas de mettre des exécutables sur votre serveur de build

Ben
la source