Escritura de pruebas unitarias para una clase que inicia EXE externo

9

Escribí una clase de C # que se usa para iniciar una lista de EXE (no uno de los míos, tengo que ejecutar EXEs de terceros) y mantenerlos en ejecución (verificaremos ocasionalmente para asegurarme de que aún se está ejecutando, e iniciarlos si no) .

Puedo probar la lógica básica de agregar, eliminar, etc. bien. ¿Cómo pruebo la unidad que el trabajo real de mantener EXE funcionará?

Mi pensamiento inicial es iniciar un EXE ficticio que se cierra después de 1 segundo, luego usarlo para probar. ¿Está fuera del ámbito de las pruebas unitarias?

MattW
fuente

Respuestas:

12

Mi pensamiento inicial es iniciar un EXE ficticio que se cierra después de 1 segundo, luego usarlo para probar. ¿Está fuera del ámbito de las pruebas unitarias?

¿Es esta una buena prueba? Claro, así que créalo. ¿Es "una prueba de unidad" en el sentido real de la palabra? No lo creo, yo llamaría a esto una "prueba del sistema" o algo así, pero eso no hace que la prueba sea menos valiosa.

Doc Brown
fuente
9

Burlarse de él en un nivel más alto que eso. Cree una clase proxy Process.Start(), falsifique eso en la prueba y verifique la entrada.

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

Donde sea que necesite consumir ClassUnderTest en el código de la aplicación, use el constructor predeterminado. En sus pruebas, pase un FakeProcessProxy al otro constructor, utilizando sus parámetros de inicio de proxy esperados y el resultado de su prueba en el constructor falso.

pdr
fuente
4

Al seguir estrictamente la filosofía de las pruebas unitarias (énfasis en la unidad ), no debe crear un archivo Exe, sino probar si su clase llama a las interfaces para generar y monitorear ese proceso correctamente. Después de todo, desea probar su clase, no la biblioteca responsable del manejo del proceso.

Pero desde un punto de vista pragmático, su enfoque está bien, aunque 1 segundo parece ser un poco largo.

keppla
fuente
1

Hice algo similar, pero acabo de llamar ping localhost. Ahorra la molestia de poner ejecutables en su servidor de compilación

Ben
fuente