Mock de Timer em Moq
2024-07-17 computer blogAcabou o dia e ainda não consegui terminar este mock dos infernos. Estou tentando criar o primeiro exemplo que usa dois wrappers nunca antes *mockados* (incluindo um timer), mas ficou faltando mockar o System.Timer. O teste já funciona, mas ele é obrigado a dar um *sleep* pra esperar o timer terminar.
O método que precisa ser testado é chamado como trigger deste timer. O teste constroi o objeto e chama um outro método de início que inicia o timer. O teste é quando o timer dispara a chamada do *callback*.
class A {
init() {
timer.init(callback);
}
callback() {
// code to be tested
}
}
Test() {
A a;
a.init();
}
Meu objetivo era que na chamada de timer.init() ele já rode o callback.
Mockar o timer foi a primeira ideia que me deram no stack overflow. Podem haver outras ideias. O cara do Stack Overflow falou que o timer do dotnet não dá essa flexibilidade, então teria que criar um adapter.
Daí eu achei um wrapper já no código e tentei modificá-lo, mas o evento contido no timer original não é acessível nem chamável e é preciso mexer nos paranauê do wrapper ou achar outro caminho.
Uma ideia que meu amigo Fábio deu foi de um timer genérico a implementar o comportamento em cima dele, mas isso eu já tenho no codebase. O wrapper pode ser usado para isso (ou uma cópia dele). Eu parei justamente nessa parte, mas escrever o código com a biblioteca Moq é que é o parto. Seus exemplos são para usos comuns e aparentemente mockar um timer não é um uso comum.
Esses resultados da internet me fazem pensar que estou indo no caminho errado (se não é comum, tá errado).
Você, caro urso, me deu uma ideia: simplificar a interface de start do TimeWrapper (esse é o nome da classe no basecode) e usar o resultado como uma implementação dummy, mas acho que já pensei num jeito de resolver que é ligeiramente diferente: ao final da tarefa ele chama um timer.Restart e daí é só ir acumulando estado.
Fiz desse jeito, que ficou bem tosco para falar a verdade, mas só de comentar na issue o TL já deu o toque pra funcionar direito. Tem que usar esta construção bizarra:
_timer.Raise(m => m.Elapsed += null, new EventArgs() as ElapsedEventArgs);
Com isso não precisa construir nenhuma classe e disparar o mock do TimerWrapper quando quiser.
A variável _timer no caso é um Mock<TimerWrapper> e o método Raise pode ser usado para disparar eventos. Isso resolve esta saga.
A próxima seria entender o que é necessário para que o Visual Studio pare de reclamar que new EventArgs() as ElapsedEventArgs pode ser null. Bom, ele pode mesmo. Porém, não tem como construir um ElapsedEventArgs sozinho no código. Ideias?