Spock
10/11/2015 11:35
1
Algum dos colegas utiliza e gosta do Spock em seus testes?
Estou tentando me acostumar com o mesmo, mas muitas vezes gasto mais tempo tentando escrever um teste simples do que escrevendo o código a ser testado, meus testes não ficam lá muito legiveis e quando algum resolve falhar não acho a saída muito explicativa

Mas obviamente é mais provavel que seja cabeçada minha, pois aparentemente se trata de uma ferramenta muito bem construída
Tags: Teste,spock


3
Oi Magno,

eu uso e gosto bastante. Meu contato inicial com a ferramenta não foi dos melhores: estava acostumado com o framework de testes padrão do Grails e então, se não me engano, na versão 2.3 eles mudaram para o Spock sem ter feito uma boa divulgação desta mudança. Em um primeiro momento apanhei bastante, pois meu modo de pensar era muito preso ao JUnit e à maneira com a qual me via habituado a escrever meus testes com ele.

No entanto, com um esforço maior fui me acostumando ao modo do Spock trabalhar e, com o tempo, acabou se tornando minha ferramenta favorita para a escrita de especificações. Pra isto minha forma de pensar estas questões foi sendo modificada com o tempo, em grande parte a algumas leituras que fiz relacionadas à prática de BDD.

Então segue aqui uma lista de fontes que me ajudaram bastante.

O texto de introdução ao BDD do Dan North teve uma influência monstruosa na minha maneira de pensar a coisa. Recomendo demais começar pela leitura dele: http://dannorth.net/introducing-bdd/
O Wiki do BDD: http://behaviourdriven.org/ (é impressionante o quão pequeno ele é)

A partir destes textos comecei a entender melhor o Spock. No entanto, alguns textos aqui também me ajudaram bastante. O grande problema com o Spock na minha opinião é o fato do site oficial do framework ser *muito* ruim e a documentação oficial no Grails também ser bastante deficitária. No entanto os textos abaixo irão lhe ajudar.

A documentação oficial do Spock: http://spockframework.github.io/spock/docs/1.0/index.html
O texto Spock Basics, no site oficial do framework - https://code.google.com/p/spock/wiki/SpockBasics

Há um terceiro texto que não estou encontrando agora, mas que o achando posto aqui pra você. 


Qualquer coisa estamos aqui pra te ajudar também, ok?


1
Então a culpa é minha mesmo... Como diria o Chapolin: Suspeitei desde o princípio :)

Andei brincando um pouco com o Spock Web Console (https://meetspock.appspot.com/) testando diversas construções para ver como ele se comporta, tem ajudado a entender um pouco melhor as coisas.

Uma pergunta: Já testou um cenário envolvendo multiplas threads?

Veja só: Eu defino alguns mocks e interações e chamo o método do service que quero testar. Este método vai abrir uma nova thread, que por sua vez vai interagir com um método mockado, que foi propositalmente ajustado para demorar alguns segundos para retornar.
Enquanto isso a thread principal continua seu trabalho, mas ao realizar qualquer interação com um mock, aparentemente a thread fica parada enquanto aquele método demorado não retornar. Parece que o framework não permite multiplas threads interagindo com os mocks


0
Oi Magno,

quando precisamos escrever validações para código que use threads, realmente a situação fica meio chata, pois seu teste pode finalizar antes das threads, levando a situações equivocadas.
Nestes casos, teria de avaliar com detalhes como está a sua situação, mas uma solução rápida seria incluir código que pausasse sua validação (Thread.sleep mesmo) por um tempo curto visando a finalização da thread e posterior verificação do estado do sistema.


0
Acho que no meu caso isso não se aplicaria...
Vou tentar descrever a situação:
Estou testando um serviço, que possui um método chamado update(). Este método carrega uma lista de objetos do banco de dados e, com base nos atributos destes objetos, escreve alguns bytes na porta serial.
Eu criei algumas interfaces para desacoplar a api de comunicação serial, então posso simular qualquer situação sem dificuldades nos testes, a saber:
SerialPortManager, que é como um factory para as portas seriais
SerialPort, que é a porta propriamente dita.

Eu identifiquei uma situação em que ao escrever um byte na porta, o método simplesmente não retorna e o serviço fica parado, então decidi que o serviço vai abrir uma nova thread que por sua vez será responsável por realizar a comunicação, e o service monitora a thread para ver se ela está demorando muito a finalizar: Se isso acontecer, ele marca um flag indicando que a porta não está respondendo, e na próxima chamada a update() ele irá forçar um close() na porta e abri-la novamente, hoje este é o código do teste:
?[code]?
@Timeout(10)
void "Se a porta demorar a responder, na próxima iteração deve ser fechada e reaberta"() {
setup:
def com3_a = Mock(SerialPort) {
1*writeByte(8) >> {
// Para simular uma porta que não responde
def initial = System.currentTimeMillis()
for (;;) {
if (System.currentTimeMillis() - initial > 20*1000)
break
}
}
}
def com3_b = Mock(SerialPort) {
1*writeByte(8)
}
when:
service.update()
service.update()

then:
1*serialPortManager.open("COM3", _) >> com3_a

then:
1*com3_a.close()

then:
1*serialPortManager.open("COM3", _) >> com3_b
}[/code]
O que acontece é que na primeira chamada a update, o método vai dar um serialPortManager.open(...), que por sua vez irá retornar o mock com3_a. Ao chamar o método writeByte, vai entrar naquele loop que demora 20 segundos para terminar.
Acontece que a chamada a writeByte é feita dentro de uma outra thread, e se o service ver que ela está levando mais de 5 segundos para terminar, vai marcar aquele flag que falei e vai seguir sua execução normalmente até retornar.
Quando da segunda chamada a update(), o service vai dar um .close() naquele mock com3_a e irá chamar novamente serialPortManager.open(...), que agora retornará o mock com3_b.
O service abre novamente a thread, chama o método .writeByte neste segundo mock, que retorna normalmente e a execução termina. O teste teria passado, só que eu anotei o método de teste com um timeout de 10 segundos, e a execução está levando em torno de 20 segundos (lembra que 20 segundos é o tempo que eu programei naquele primeiro mock?)

Através dos logs produzidos pelo service, pude constatar que a segunda chamada a serialPortManager.open() só retorna depois que terminam os 20 segundos que começaram a contar quando daquela chamada a writeBytes lá atras, o que me leva a crer que qualquer chamada a um método mockado só vai ocorrer quando qualquer chamada anterior tiver terminado (mesmo sendo em threads diferentes).


0
Consegui resolver o problema.
De fato parece ser uma limitação do spock que duas threads não conseguem chamar métodos de mocks ao mesmo tempo, então aquele mock de porta serial que demora a retornar eu implementei usando simplemente uma classe anonima... como trata-se de uma interface bem simples, foi tranquilo



Ainda não faz parte da comunidade???

Para se registrar, clique aqui.


Aprenda Groovy e Grails com a Formação itexto!

Newsletter Semana Groovy

Assinar

Envie seu link!


Livro de Grails


/dev/All

Os melhores blogs de TI (e em português) em um único lugar!

 
Creative Commons
RSS Grails Brasil é mantido por itexto Consultoria.
Em caso de problemas contacte Henrique Lobo Weissmann (Kico) por e-mail: kico@itexto.com.br
Todo o conteúdo presente neste site adota o Creative Commons como licença padrão.
Ver: 4.14.0
itexto