Pergunta

Eu estou usando C # 3.0 e NUnit. Eu estou querendo saber se existe uma maneira padrão para realizar testes de unidade no código que é executado após uma certa quantidade de tempo. Por exemplo, eu tenho uma classe estática simples que posso registar métodos com, e tê-los ser chamado n milissegundos mais tarde. Eu preciso para garantir que o código nos métodos de delegado está sendo chamado.

Por exemplo, o seguinte teste será sempre passar, porque não existem afirmações feitas até depois que o método foi encerrado.

[Test]
public void SampleTest()
{
    IntervalManager.SetTimeout(delegate{ 
        Assert.Equals(now.Millisecond + 100, DateTime.Now.Millisecond); 
    }, 100);
}

É possível até mesmo código de teste de unidade que não executar imediatamente?

Cheers,

Paul

Foi útil?

Solução

Como sobre isso? Isso faz com que o teste para o bloco durante algum tempo máximo esperado para o retorno ao fogo e completa antes fiando, relatando um erro.

public void Foo() {
    AutoResetEvent evt = new AutoResetEvent(false);
    Timer t = new Timer(state => {
        // Do work
        evt.Set();
    }, null, 100, Timeout.Infinite);
    if (evt.WaitOne(500)) {
        // method called and completed
    } else {
        // timed out waiting
    }
}

Outras dicas

Então, o que exatamente você está testando? Você está testando que Timers trabalho? Ou que seu código corretamente configura um temporizador para que na expiração do temporizador executa uma chamada de retorno? Sem saber o que os olhares código como, eu estou supondo que o que você realmente quer teste é o último. Minha resposta seria que (1) este é, provavelmente, vai ser difícil com os métodos estáticos e (2) você provavelmente vai precisar injectável dependência e injetar os temporizadores de simulação, etc., que na verdade não executar o método resultando mas recorde via expectativas de que as chamadas apropriadas foram feitas por seu código.

Como uma nota lateral. Nós geralmente tentar marcar nossos testes com execução lenta com um NUnit categoria pode optar por ignorar esses testes em algumas compilações.

Sim, fazê-lo como no seu exemplo não irá funcionar.

Em vez disso, eu recomendo que você criar uma classe de teste, para ser usado como o delegado, que os registros quando seu método foi chamado, e em que momento.

Você, em seguida, injetar o seu simulada no IntervalManager você deseja testar. Seu método de teste, então tem que esperar para o IntervalManager (usando um método adequado fornecido pelo IntervalManager, ou apenas esperar alguns segundos), então você pode verificar o estado da classe de teste.

BTW, esta abordagem é normalmente referido como zombeteiro ; neste caso a classe de teste seria o objeto fictício.

Como um par de outras respostas indicaram, os testes de longa execução são geralmente uma má idéia. Para facilitar a testar este componente você deve considerar que você realmente tem duas coisas distintas que você está tentando teste.

  1. Quando se regista uma execução delegado cronometrado o tempo adequado está definido. Isso provavelmente precisa ser testado com várias combinações de tempos de espera eo número de delegados.
  2. O delegado é executado de forma adequada.

Separar os testes da maneira que lhe permitem testar se o mecanismo de tempo funciona como esperado, com um pequeno número de limites de tempo curtos (testando todos os casos, você precisa considerar). Lembre-se que você provavelmente vai precisar de um pouco de margem de manobra no tempo real que é preciso para executar um determinado delegado com base na carga atual no sistema e quão complexo o seu código componente é (que está em IntervalManager).

Claro que você pode testá-lo. Você apenas tem que esperar por ele para executar.

Talvez eu estou faltando alguma coisa, mas o teste de unidade do Visual Studio tem atributos especiais que você pode colocar em métodos para a ordem de execução de controle e outras coisas. Isto deveria ter sido gerado automaticamente quando você fez pela primeira vez o projeto de teste de unidade:

    #region Additional test attributes
    // 
    //You can use the following additional attributes as you write your tests:
    //
    //Use ClassInitialize to run code before running the first test in the class
    //[ClassInitialize]
    //public static void MyClassInitialize(TestContext testContext) {
    //}
    //
    //Use ClassCleanup to run code after all tests in a class have run
    //[ClassCleanup()]
    //public static void MyClassCleanup()
    //{
    //}
    //
    //Use TestInitialize to run code before running each test
    //[TestInitialize()]
    //public void MyTestInitialize()
    //{
    //}
    //
    //Use TestCleanup to run code after each test has run
    //[TestCleanup()]
    //public void MyTestCleanup()
    //{
    //}
    //
    #endregion

Então, usando [ClassInitialize] deve permitir que você escrever o que tem para executar pela primeira vez em um método. Em seguida, os testes podem ser executados. Ou você pode usar [TestInitialize] para executar código antes de cada teste.

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