Pregunta

Tenemos algunas pruebas NUnit que acceden a la base de datos. Cuando uno de ellos falla se puede dejar en la base de datos inconsistentes del estado - que no es un problema, ya que reconstruir la base de datos para cada prueba -. Pero puede causar otras pruebas para fallar en la misma prueba

¿Es posible detectar que una de las pruebas fallaron y realizar algún tipo de limpieza?

No queremos escribir código de limpieza en todas las pruebas, que ya hacemos ahora. Me gustaría perfrom limpieza de desmontaje, pero sólo si la prueba falló, como la limpieza podría ser costoso.

Actualizar : Para aclarar - Me gustaría pruebas para ser simple y no incluye ninguna limpieza o tratamiento de errores de lógica. Asimismo, no quiero realice la reposición de base de datos en cada prueba - solamente si la prueba falla. Y este código, probablemente, se debe ejecutar en el método de desmontaje, pero no estoy al tanto de alguna manera de obtener información si prueba que actualmente están destruyendo desde fallado o se ha realizado correctamente.

Update2

        [Test]
        public void MyFailTest()
        {
            throw new InvalidOperationException();
        }

        [Test]
        public void MySuccessTest()
        {
            Assert.That(true, Is.True);
        }

        [TearDown]
        public void CleanUpOnError()
        {
            if (HasLastTestFailed()) CleanUpDatabase();
        }

Busco implementación de HasLastTestFailed ()

¿Fue útil?

Solución

Esta idea me interesó, así que hice un poco de investigación. NUnit no tiene esta capacidad fuera de la caja, pero no hay un marco de extensibilidad toda suministrado con NUnit. He encontrado este gran artículo sobre la que se extiende NUnit - era un buen punto de partida. Después de jugar un rato con él, me ocurrió con la siguiente solución: un método decorado con un atributo CleanupOnError personalizada será llamado si una de las pruebas en el aparato falló

.

Así es como la prueba será similar a:

  [TestFixture]
  public class NUnitAddinTest
  {
    [CleanupOnError]
    public static void CleanupOnError()
    {
      Console.WriteLine("There was an error, cleaning up...");
      // perform cleanup logic
    }

    [Test]
    public void Test1_this_test_passes()
    {
      Console.WriteLine("Hello from Test1");
    }

    [Test]
    public void Test2_this_test_fails()
    {
      throw new Exception("Test2 failed");
    }

    [Test]
    public void Test3_this_test_passes()
    {
      Console.WriteLine("Hello from Test3");
    }
  }

donde el atributo es simplemente:

  [AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = false)]
  public sealed class CleanupOnErrorAttribute : Attribute
  {
  }

Y aquí es cómo se ejecuta desde el complemento:

public void RunFinished(TestResult result)
{
  if (result.IsFailure)
  {
    if (_CurrentFixture != null)
    {
      MethodInfo[] methods = Reflect.GetMethodsWithAttribute(_CurrentFixture.FixtureType,
                                                             CleanupAttributeFullName, false);
      if (methods == null || methods.Length == 0)
      {
        return;
      }

      Reflect.InvokeMethod(methods[0], _CurrentFixture);
    }
  }
}

Pero aquí está la parte difícil: el complemento se debe colocar en el directorio addins al lado del corredor NUnit. Mina se colocó al lado del corredor NUnit en el directorio TestDriven.NET:

  

C:\Program Files\TestDriven.NET 2.0\NUnit\addins

(creé el directorio addins, que no estaba allí)

Editar Otra cosa es que el método de limpieza necesita ser static!

I hackeado un complemento simple, se puede descargar el código fuente de mi SkyDrive . Usted tendrá que añadir referencias a nunit.framework.dll, nunit.core.dll y nunit.core.interfaces.dll en los lugares apropiados.

Algunas notas: La clase de atributo se puede colocar en cualquier lugar de su código. No quería colocarlo en la misma Asamblea que el propio complemento, porque hace referencia a dos asambleas Core NUnit, así que coloqué en un montaje diferente. Sólo recuerde que debe cambiar la línea en el CleanAddin.cs, si decide ponerlo en otro sitio.

Espero que ayude.

Otros consejos

Desde la versión 2.5.7, NUnit permite desmontaje para detectar si la última prueba ha fallado. Una nueva clase TestContext permite pruebas para acceder a la información sobre sí mismos incluyendo los TestStauts.

Para más detalles, consulte http://nunit.org/?p=releaseNotes&r = 2.5.7

[TearDown]
public void TearDown()
{
    if (TestContext.CurrentContext.Result.Status == TestStatus.Failed)
    {
        PerformCleanUpFromTest();
    }
}

Si bien puede ser posible coaccionar nUnit en hacer esto no es el diseño más sensible, siempre se puede configurar un archivo temporal en algún lugar y si ese archivo existe, ejecuta su limpieza.

Yo recomendaría cambiar su código para que haya habilitado base de datos las transacciones y al final de la prueba, basta con volver la base de datos a su estado original (por ejemplo, se descarta la transacción que representa su unidad de pruebas).

Sí, la hay. Puede utilizar el desmontaje atributo , que se tearDown después de cada prueba. Lo que quiere aplicar esa base de datos "reset" script que tiene y desmontaje y re-configuración antes y después de cada prueba.

  

Este atributo se utiliza dentro de una   TestFixture para proporcionar un conjunto común de   funciones que se realizan después de   cada método de prueba se ejecuta.

Actualizar : Sobre la base de los comentarios y actualización a la pregunta, yo diría que se puede utilizar el atributo desmontaje y utilizar variables privadas para indicar si el contenido método debe disparar.

Aunque, también vio que no desea ningún código de control de la lógica o de error compleja.

Teniendo en cuenta que, yo creo que una configuración estándar / desmontaje trabajar sería mejor para usted. No importa si hay un error y usted no tiene que tener ningún código de control de errores.

Si necesita limpieza especial debido a las próximas pruebas depende de la finalización con éxito de la prueba actual, me gustaría sugerir a revisar sus pruebas -. Que probablemente no deberían depender unos de otros

¿Qué pasa con el uso de un bloque try-catch, Regeneración de la excepción capturada?

try
{
//Some assertion
}
catch
{
     CleanUpMethod();
     throw;
}

Me gustaría hacer como phsr sugiere por ahora y cuando se lo puede permitir, refactorizar las pruebas para que nunca tienen que depender de los mismos datos que otras necesidades de prueba o incluso mejor abstraer el acceso a datos de la capa y se burlan de los resultados procedentes de esa base de datos. Suena como sus pruebas son bastante caros y que usted debe hacer todo su lógica de consulta en la base de datos de la lógica y de negocios en el ensamblado, realmente no importa lo que se se devuelven los resultados.

También será capaz de probar su ExceptionHandling mucho mejor.

Otra opción es tener una función especial que lanzan sus excepciones, que establece un interruptor en la TestFixture dice que se produjo una excepción.

public abstract class CleanOnErrorFixture
{
     protected bool threwException = false;

     protected void ThrowException(Exception someException)
     {
         threwException = true;
         throw someException;
     }

     protected bool HasTestFailed()
     {
          if(threwException)
          {
               threwException = false; //So that this is reset after each teardown
               return true;
          }
          return false;
     }
}

A continuación, utilizando el ejemplo:

[TestFixture]
public class SomeFixture : CleanOnErrorFixture
{
    [Test]
    public void MyFailTest()
    {
        ThrowException(new InvalidOperationException());
    }

    [Test]
    public void MySuccessTest()
    {
        Assert.That(true, Is.True);
    }

    [TearDown]
    public void CleanUpOnError()
    {
        if (HasLastTestFailed()) CleanUpDatabase();
    }
}

El único problema aquí es que el seguimiento de pila dará lugar a la CleanOnErrorFixture

Una opción no mencionado hasta ahora es envolver la prueba en un objeto TransactionScope, por lo que no importa lo que sucede a medida que la prueba no compromete nada a la base de datos.

Esto es algunos detalles sobre la técnica . Usted probablemente puede encontrar más si se hace una búsqueda en la unidad de pruebas y TransactionScope (aunque realmente está haciendo pruebas de integración si se golpea un DB). Lo he utilizado con éxito en el pasado.

Este enfoque es simple, no requiere ningún tipo de limpieza y asegura que están aislados pruebas.

Editar- he di cuenta de respuesta Ray Hayes es también similar a la mía.

¿De qué falló? ¿Es posible ponerlo en un intento (ver prueba) / catch (db fijar roto) / finally?

O puede llamar a un método privado para fijarlo cuando se haya comprobado su condición a prueba.

No estoy diciendo que esto es una gran idea, pero debería funcionar. Recuerde que los errores de aserción son sólo excepciones. Asimismo, no se olvide que también es un atributo [TestFixtureTearDown] que se ejecuta sólo una vez después de todas las pruebas en el aparato han corrido.

El uso de estos dos hechos se puede escribir algo como el establecimiento de una bandera si un pruebas fallaron y comprobando el valor de la bandera en el dispositivo de prueba derribe.

No recomiendo esto, pero que iba a funcionar. Usted no está realmente utilizando NUnit como estaba previsto, pero puede hacerlo.


[TestFixture]
public class Tests {
     private bool testsFailed = false;

     [Test]
     public void ATest() {
         try {
             DoSomething();
             Assert.AreEqual(....);
         } catch {
            testFailed = true;
         }
     }

     [TestFixtureTearDown]
     public void CleanUp() {
          if (testsFailed) {
              DoCleanup();
          }
     }
}

Puede agregar un método [TearDown] con
if (TestContext.CurrentContext.Result.Status != TestStatus.Passed)
algo de código que se ejecutará si la prueba falló.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top