No último post apresentei o uso de Mocks para conseguir testar as classes que ainda estão sendo desenvolvidas usando objetos das quais elas dependem sem ter que implementar tais objetos. Neste post, como era de se esperar, eu vou explorar melhor o uso do Rhino Mocks, mostrando as principais opções que ele dispõe no uso de Mocks.
Mas, antes de continuar, eu me esqueci de instruir o básico a respeito do Rhino.
O Rhino é um framework que pode ser baixado em http://www.ayende.com/projects/rhino-mocks.aspx.
Neste site, você tem, também, toda a documentação disponível.
Até mesmo eu preciso rever o Rhino para descobrir se tem algo dele que deixei de explorar. O fato é que o pouco que sei já me torna capaz de fazer um uso excelente dele. Para usá-lo é simples, basta colocar no seu projeto uma referência a Rhino.Mocks.Dll.
As principais classes do Rhino se encontram no Namespace Rhino.Mocks.
A principal classe que você vai usar é a Rhino.Mocks.MockRepository.
Uma instância de MockRepository irá servir para criar seus Mocks e monitorá-los.
Vamos rever o exemplo do último post:
//setup var mocks = new Rhino.Mocks.MockRepository(); ICustomerBusiness objBusCustomer = mocks.StrictMock<ICustomerBusiness>(null); ILogger objLogger = mocks.StrictMock<ILogger>(null);
Observe que é da instancia de MockRepository (mocks) que executamos o método StrictMock<T>, que gera para nós o mock baseado baseado no tipo passado.
mocks.Record();
objBusCustomer.InsertCustomer(Customer);
objLogger.WriteLog("Cliente Inserido");
mocks.ReplayAll();
//exercise
Controller.InsertCustomer(Customer);
//verify
mocks.VerifyAll();
O método Record() faz com que o MockRepository (mocks) passe a monitorar tudo o que acontece com os mocks criados. Assim, quando invocamos o método InsertCustomer do mock de ICustomerBusiness, a instância de MockRepository compreende esta chamada e deixa guardada, bem como a chamada ao método WriteLog do mock de ILogger.
Quando invocamos o método ReplayAll(), a instância de MockRepository começa passa a monitorar os mocks esperando que tudo o que aconteceu durante a gravação (Record()) aconteça novamente. A forma como administramos o MockRepository para se comportar de acordo com o que acontece durante o ReplayAll() vai depender do tipo de mocks que criamos. No caso do StrictMock<T>, que foi o que usamos para criar os mocks que estão sendo usados, o MockRepository espera que aconteça exatamente tudo o que aconteceu durante a gravação, nada mais, e nada menos. Se no meio do caminho acontecer algo que ele não tinha gravado, ele lança uma exception.
Quando finalmente chegamos no VerifyAll, a instância de MockRepository verifica se tudo que de fato deveria acontecer, aconteceu. Ou seja, ele garante em que ponto que tudo o que deveria acontecer no ReplayAll() já deveria ter acontecido. Se algum método tiver sido deixado de ser chamado, uma exception será lançada.
O que garante o sucesso dos testes é que o método InsertCustomer do Controller faz exatamente o que orientamos o objeto Mocks a gravar. Ou seja, usamos o Record para definir o comportamento esperado, e então usamos o ReplayAll() para iniciar a verficação de que este comportamento realmente está sendo obedecido pelo objeto que estamos testando.
Se você entrar no método InsertCustomer do Controller e inserir um novo log, ao rodar o teste, ele dará uma falha (vermelho) pois o mocks só gravou uma única chamada ao WriteLog. Se o parâmetro do WriteLog for diferente do que foi gravado, também ocorrerá uma falha.
Desta forma, o código do último post fica mais claro e você pode entender melhor o que está acontecendo aqui.
Mas, como mockar um objeto que possui um método cujo os parâmetros da chamada eu sou incapaz prever? E como entender se um método funciona se o seu bom funcionamento depende do retorno da chamada de um método de um objeto mockado?
Isso tudo está na pauta para o nosso próximo post, que espero ter condições de redigir logo e publicar em breve.
Stay Sharp!
Não pare por aqui. Seus posts são muito bons.
Você poderia falar um pouco sobre stubs também. Sempre tive dúvidas na diferença entre Mocks e Stubs.
Abraços.
Meu amigo, já estou a mais de 1 anos esperando a continuação de seus posts de TDD. Não esquece de nós.
Um Abraço.