Pergunta

Temos alguns testes NUnit que acessam o banco de dados. Quando um deles não pode deixar de banco de dados em estado inconsistente - que não é um problema, uma vez que reconstruir banco de dados para cada teste -. Mas pode causar outros testes de falhar no mesmo prazo

É possível detectar que um dos testes que falharam e realizar algum tipo de limpeza?

Nós não quero escrever código de limpeza em todos os testes, nós já fazemos isso agora. Eu gostaria de limpeza perfrom em Teardown mas apenas se o teste falhou, como a limpeza pode ser caro.

Atualização : Para esclarecer - eu gostaria testes para ser simples e não incluem qualquer limpeza ou erro de manipulação lógica. Eu também não quero realizar a reposição de banco de dados em cada teste - somente se teste falhar. E este código provavelmente deve ser executado no método Teardown mas eu não tenho conhecimento de qualquer maneira para obter informações se o teste atualmente estamos derrubando a partir falhou ou foi bem sucedido.

Update2 :

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

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

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

Eu estou olhando para a implementação de HasLastTestFailed ()

Foi útil?

Solução

Esta ideia me interessou, então eu fiz um pouco de escavação. não NUnit não têm essa capacidade para fora da caixa, mas há uma estrutura de extensibilidade todo fornecido com NUnit. Eu encontrei este excelente artigo sobre como estender NUnit - foi um bom ponto de partida. Depois de brincar com ele, eu vim com a seguinte solução: um método decorado com um atributo CleanupOnError personalizado será chamado se um dos testes no dispositivo elétrico falhou

.

Veja como a aparência do teste como:

  [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");
    }
  }

onde o atributo é simplesmente:

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

E aqui está como ele é executado a partir do suplemento:

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

Mas aqui está a parte complicada: o suplemento deve ser colocado no diretório addins ao lado do corredor NUnit. O meu foi colocado ao lado do corredor NUnit no diretório TestDriven.NET:

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

(I criou o diretório addins, ela não estava lá)

Editar Outra coisa é que o método de limpeza precisa ser static!

Eu cortei juntos um simples suplemento, você pode baixar o código fonte de meu SkyDrive . Você terá que adicionar referências a nunit.framework.dll, nunit.core.dll e nunit.core.interfaces.dll nos lugares apropriados.

Algumas notas: A classe atributo pode ser colocado em qualquer lugar em seu código. Eu não queria colocá-lo no mesmo assembly como o próprio suplemento, porque faz referência a dois conjuntos Core NUnit, então eu colocá-lo em uma montagem diferente. Apenas lembre-se de alterar a linha no CleanAddin.cs, se você decidir colocá-lo em qualquer outro lugar.

Espero que ajude.

Outras dicas

Desde a versão 2.5.7, NUnit permite Teardown para detectar se último teste falhou. Uma nova classe TestContext permite testes para acessar informações sobre si, incluindo as TestStauts.

Para mais detalhes, consulte a http://nunit.org/?p=releaseNotes&r = 2.5.7

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

Embora possa ser possível para coagir nUnit para fazer isso, ele não é o projeto o mais sensato, você sempre pode definir um arquivo temporário em algum lugar e se existe esse arquivo, execute sua limpeza.

Eu recomendaria alterar seu código para que você tenha de banco de dados-transações habilitado e no final do teste, simplesmente reverter o banco de dados para o estado original (por exemplo, descartar a transação que representa as suas unidades-testes).

Sim, existe. Você pode usar o Teardown atributo que vai desmontagem após cada teste. Você gostaria de aplicar esse banco de dados script de "reset" que você tem e desmontagem e re-configuração antes e depois de cada teste.

Este atributo está dentro usou um TestFixture para fornecer um conjunto comum de funções que são executadas depois cada método de teste é executado.

Atualizar : Com base nos comentários e atualização para a questão, eu diria que você pode usar o atributo de desmontagem e usar variáveis ??privadas para indicar se o conteúdo método deve disparar.

Embora, eu também ver que você não quer qualquer código lógica ou erro de manipulação complexa.

Tendo em conta que, eu acho que uma configuração standard / Teardown iria funcionar melhor para você. Não importa se há um erro e você não tem que ter qualquer código de manipulação de erro.

Se você precisa-se limpo especial, porque os próximos testes depende da conclusão bem-sucedida do teste atual, sugiro rever seus testes -. Eles provavelmente não deve depender de si

Que tal usar um bloco try-catch, rethrowing exceção pego?

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

Eu faria como phsr sugere para agora e quando você puder pagar, refatorar os testes para que eles nunca tem que contar com os mesmos dados que mais necessidades de teste ou ainda melhor abstrair a camada de acesso a dados e zombar dos resultados provenientes de esse banco de dados. Parece que seus testes são bastante caros e você que você deve fazer toda a lógica sua consulta sobre a lógica de banco de dados e de negócios em sua montagem que você realmente não me importo o que os resultados são retornados.

Você também será capaz de testar o seu ExceptionHandling muito melhor.

Outra opção é ter uma função especial que vai jogar suas exceções, que define uma opção no TestFixture que diz uma exceção ocorreu.

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

Em seguida, usando o seu exemplo:

[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();
    }
}

O único problema aqui é que o rastreamento de pilha levará à CleanOnErrorFixture

Uma opção não mencionado até agora é envolver o teste em um objeto TransactionScope, por isso não importa o que acontece quando o teste nunca comete qualquer coisa para o DB.

Aqui está alguns detalhes sobre a técnica . Você provavelmente pode encontrar mais se você fizer uma pesquisa no teste de unidade e TransactionScope (embora você está realmente fazendo testes de integração se você bater um DB). Eu usei-o com sucesso no passado.

Esta abordagem é simples, não requer qualquer limpeza e garante que os testes são isolados.

Edit- eu só notei resposta Ray Hayes também é semelhante ao meu.

Como se falhar? É possível colocá-lo em uma tentativa (do teste) / catch (correção db quebrado) / bloco finally?

Ou você poderia chamar um método particular para corrigi-lo quando você já tiver verificado a sua falha condição.

Eu não estou dizendo que isso é uma grande idéia, mas deve funcionar. Lembre-se que falhas de declaração são apenas exceções. Também não se esqueça há também um atributo [TestFixtureTearDown] que é executado apenas uma vez depois de todos os testes no dispositivo elétrico ter executado.

Usando esses dois fatos que você pode escrever algo como definir um sinalizador se alguns testes falharam e verificando o valor da bandeira no baixo dispositivo de ensaio lágrima.

Eu não recomendo isso, mas ele iria trabalhar. Você não está realmente usando NUnit como pretendido, mas você pode fazê-lo.


[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();
          }
     }
}

Você pode adicionar um método [TearDown] com
if (TestContext.CurrentContext.Result.Status != TestStatus.Passed)
algum código a ser executado se o teste falhou.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top