Minha preferência é ter aulas que usam o tempo na verdade dependem de uma interface, como
interface IClock
{
DateTime Now { get; }
}
Com uma implementação concreta
class SystemClock: IClock
{
DateTime Now { get { return DateTime.Now; } }
}
Então, se quiser, você pode fornecer qualquer outro tipo de relógio que deseja para teste, como
class StaticClock: IClock
{
DateTime Now { get { return new DateTime(2008, 09, 3, 9, 6, 13); } }
}
Pode haver alguma sobrecarga em fornecer o relógio para a classe que depende dele, mas isso pode ser tratado por qualquer número de soluções de injeção de dependência (usando um contêiner de Inversão de Controle, injeção simples de construtor / setter ou até mesmo um Padrão de Gateway Estático )
Outros mecanismos de entrega de um objeto ou método que fornece os tempos desejados também funcionam, mas acho que o principal é evitar redefinir o relógio do sistema, já que isso apenas introduzirá dor em outros níveis.
Além disso, usá DateTime.Now
-lo e incluí-lo em seus cálculos não parece certo - ele rouba a capacidade de testar horários específicos, por exemplo, se você descobrir um bug que só acontece próximo ao limite da meia-noite ou às terças-feiras. Usar a hora atual não permitirá que você teste esses cenários. Ou pelo menos não quando quiser.
UtcNow
deve ser usado e, em seguida, ajustado de acordo com a preocupação do código, por exemplo, lógica de negócios, IU, etc. A manipulação de DateTime em fusos horários é um campo minado, mas o melhor primeiro passo a frente é sempre começar com Hora UTC.Ayende Rahien usa um método estático que é bastante simples ...
fonte
Acho que criar uma classe de relógio separada para algo simples como obter a data atual é um pouco exagero.
Você pode passar a data de hoje como um parâmetro para que possa inserir uma data diferente no teste. Isso tem o benefício adicional de tornar seu código mais flexível.
fonte
Usar o Microsoft Fakes para criar um shim é uma maneira realmente fácil de fazer isso. Suponha que eu tivesse a seguinte aula:
No Visual Studio 2012, você pode adicionar um assembly Fakes ao seu projeto de teste clicando com o botão direito do mouse no assembly para o qual deseja criar Fakes / Shims e selecionando "Add Fakes Assembly"
Finalmente, aqui está a aparência da classe de teste:
fonte
A chave para um teste de unidade bem-sucedido é o desacoplamento . Você tem que separar seu código interessante de suas dependências externas, para que ele possa ser testado isoladamente. (Felizmente, o Desenvolvimento Orientado a Testes produz código desacoplado.)
Neste caso, seu externo é o DateTime atual.
Meu conselho aqui é extrair a lógica que lida com DateTime para um novo método ou classe ou o que fizer sentido no seu caso, e passar DateTime. Agora, seu teste de unidade pode passar um DateTime arbitrário para produzir resultados previsíveis.
fonte
Outra usando Microsoft Moles ( Isolation framework for .NET ).
fonte
Eu sugiro usar o padrão IDisposable:
Descrito em detalhes aqui: http://www.lesnikowski.com/blog/index.php/testing-datetime-now/
fonte
Resposta simples: vala System.DateTime :) Em vez disso, use o NodaTime e sua biblioteca de testes: NodaTime.Testing .
Leitura adicional:
fonte
Você poderia injetar a classe (melhor: método / delegado ) para usar
DateTime.Now
na classe que está sendo testada. DeveDateTime.Now
ser um valor padrão e apenas configurá-lo no teste para um método fictício que retorna um valor constante.EDIT: O que Blair Conrad disse (ele tem algum código para olhar). Exceto, eu tendo a preferir delegados para isso, já que eles não bagunçam sua hierarquia de classes com coisas como
IClock
...fonte
Enfrentei essa situação com tanta frequência que criei um nuget simples que expõe a propriedade Now por meio da interface.
A implementação é, obviamente, muito simples
Depois de adicionar o nuget ao meu projeto, posso usá-lo nos testes de unidade
Você pode instalar o módulo diretamente do GUI Nuget Package Manager ou usando o comando:
E o código do Nuget está aqui .
O exemplo de uso com o Autofac pode ser encontrado aqui .
fonte
Você já considerou o uso de compilação condicional para controlar o que acontece durante a depuração / implantação?
por exemplo
Caso contrário, você deseja expor a propriedade para que possa manipulá-la, tudo isso faz parte do desafio de escrever código testável , que é algo que estou lutando atualmente: D
Editar
Uma grande parte de mim preferiria a abordagem de Blair . Isso permite que você "conecte" partes do código para ajudar no teste. Tudo segue o princípio de design encapsular o que varia o código de teste não é diferente do código de produção, apenas ninguém o vê externamente.
A criação e a interface podem parecer muito trabalhosas para este exemplo (razão pela qual optei pela compilação condicional).
fonte
DateTime
'sNow
eToday
etc.