tdd - algumas lições aprendidas com o livro goos
Post on 11-Jun-2015
1.966 Views
Preview:
DESCRIPTION
TRANSCRIPT
- 1. Test Driven Development
- Fbio Luiz Nery de Miranda baseado no livroGrowing OO Software Guided by Tests
2. Roadmap
- Problema: autenticao em um service provider de terceiros.
3. TDD:RedGreenRefactor 4. Testes de Unidadex Testes de Integrao 5. Ports and Adapters Pattern
- (Business Domain versus Technical Domain)
Testes de Unidade com JMock 6. Coverage Tests 7. Logging Tests 8. Autenticao num Service Provider de Terceiros
- API REST / XML
POST http://isp-authenticator.dev.globoi.com:8280/ws/rest/autenticacao XML Resquest Autenticao: 303a6a6f616f646576406d61696cfulano123456127.0.0.1 XML Response Autenticao fab1@spam.la12257993f74d2b1ffab1@spam.laAUTENTICADOATIVONAO_ASSINANTE21588993 9. Por onde comear?
- Defina a classe de domnio que deseja testar (System Under Test SUT)
10. Queremos uma classe que realize autenticao (um Authenticator) 11. O ponto de partida ser AuthenticatorTests 12. Qual o foco do teste? O nome do teste expressa a inteno?
- Defina o foco do teste, criando um mtodo de teste cujo nome expresse a inteno
- (Ajuda a no se afastar do foco)
Um Authenticator deve realizar autenticao caso o nome do usurio e a senha estejam corretos. 13. @Test 14. public void shouldAuthenticateWhenCredentialsAreValid() { 15. } 16. Exercitando o teste
- Comece a implementar o teste exercitando o SUT (mesmo que o SUT ainda no exista)
17. @Test 18. public void shouldAuthenticateWhenCredentialsAreValid() {
-
- AuthenticationResponse response = authenticator.authenticate(validUsername, validPassword);
} 19. Setup e Assertions
- Faa as asseres e o setup necessrios.
20. private final Authenticator authenticator = new Authenticator(); 21. private final String validUsername = valid@userna.me; 22. private final String validUsername = va1idpassw0rd; 23. @Test 24. public void shouldAuthenticateWhenCredentialsAreValid() {
-
- AuthenticationResponse response = authenticator.authenticate(validUsername, validPassword);
- 25. assertThat(authentication response, response, is(notNullValue()));
26. assertThat(authentication response, response.isAuthenticated(), is(true)); } 27. Implemente as classes do domnio (stubs vazios)
- Crie as classes, mas apenas o suficiente para desaparecerem os erros de compilao.
28. Observe o testefalhar 29. A mensagem de falha do teste expressa suficientemente bem o que est quebrado? 30. A importncia de falhar antes
- Evitar falsos positivos
31. Promove boas prticas dediagnstico de falhas (GOOS Best Practice!)
- A clareza nas mensagens de falha muito importante
32. Elas ajudaro a diagnosticar problemas, quando novas features provoquem quebra de cdigo existente. 33. A ausncia de mensagens claras sobre a falha forar o desenvolvedor a ter que ler e entender a implementao para saber o que quebrou (pior caso: quando o dev que fez quebrar o cdigo no o prprio autor do cdigo) Hamcrest Library: matchers so synthax sugar e ajudam a criar mensagens de falha mais detalhadas. 34. Implemente o cdigomais simplesque permita o testePASSAR
- No precisa implementar toda a lgica complexa de uma s vez
35. KISS Keep It Simple 36. No perca o foco do teste. 37. No se distraia com premissas que devem ser validadas em outros testes. 38. DONE?
- O que o Authenticator deveria fazer?
- POST num servio REST/XML
O que o Authenticator est fazendo? publicAuthenticationResponse authenticate(String username, String password)throwsAuthenticationFailure { return newAuthenticationResponse();// lazy boy... } public classAuthenticationResponse { publicBoolean isAuthenticated() { return true ;// aham... } }
- Authenticator um fanfarro...
39. Pausa para Reflexo
- Authenticator deve se preocupar com os detalhes de como a autenticao realizada?
40. Resposta: Depende (nenhuma verdade absoluta) 41. Se est interessado em criar um Domain Model, importante separar classes de domnio das classes que possuem detalhes tcnicos de como a funcionalidade implementada. 42. Ports and Adapters Pattern
- Ports: interfaces p/ abstrair relaes domnio x dependncias externas)
43. Adapters: implementam as interfaces, encapsulando o domnio tcnico da aplicao 44. Testes de Unidade: verificam o comportamento do Authenticator. 45. Testes de Integrao: verificam a implementao do delegate. 46. Ports and Adapters Pattern (GOOS) 47. Retornando foco ao teste...
- Queremos saber se o Authenticator comanda corretamente o delegate, sem se preocupar em como o delegate ser implementado.
privateMockerycontext=newMockery(); private finalAuthenticator.Delegatedelegate=context .mock(Authenticator.Delegate. class ); privateAuthenticatorauthenticator=newAuthenticator( delegate ); @Test public voidshouldAuthenticateSucessfully()throwsException { context .checking( newExpectations() {{ AuthenticationResponse sucessfullAuthentication =newAuthenticationResponse(); sucessfullAuthentication.setAuthenticated( true ); oneOf( delegate ).performAuthentication(with( validUsername ), with( validPassword )); will( returnValue (sucessfullAuthentication)); }}); AuthenticationResponse response =authenticator .authenticate( validUsername ,validPassword ); assertThat ( "authentication response" , response,is ( notNullValue ())); assertThat ( "authentication response" , response.isAuthenticated(),is ( true )); } 48. Rodando os Testes...
- Pegadinha do Malandro: @RunWith(JMock.class), para o Jmock verificar se os Mock Objects do contexto foram executados de acordo com as expectativas.
49. Falhar o teste : o teste falha de forma clara, facilitando o correto diagnstico? 50. Corrigir Authenticator e AuthenticationResponse epassar 51. DONE?
- A classe Authenticator est coberta por testes de unidade.
52. O Delegate responsvel pela autenticao via POST/XML injetado no Authenticator, via construtor. 53. Resta prover uma implementao do Delegate um RestTemplateDelegate, por exemplo e escrever um teste de integrao. 54. Teste de Integrao @RunWith (SpringJUnit4ClassRunner. class ) @ContextConfiguration (locations= "classpath:beans.xml" ) public classRestTemplateAuthenticatorTests { @Autowired privateRestTemplateAuthenticationDelegaterestTemplateDelegate ; privateAuthenticatorauthenticator ; @Before public voidsetup() { authenticator=newAuthenticator( restTemplateDelegate ); } @Test public voidauthenticateUser()throwsException { assertTrue ( authenticator .authenticate( "fab1@spam.la" ,"teste123456" ).isAuthenticated()); } 55. RestTemplateAutenticationDelegate public classRestTemplateAuthenticationDelegateimplementsAuthenticator.Delegate { private finalStringurl ; private finalRestTemplaterest ; publicRestTemplateAuthenticationDelegate(String url, RestTemplate rest) { this . url= url; this . rest= rest; } publicAuthenticationResponse performAuthentication(String username, String password)throwsAuthenticationFailure { try{ XmlAuthenticationRequest xmlRequest =newXmlAuthenticationRequest(); xmlRequest.setIp( "127.0.0.1" ); xmlRequest.setLogin(username); xmlRequest.setSenha(password); XmlAuthenticationResponse xmlResponse =rest .postForObject( url , xmlRequest, XmlAuthenticationResponse. class ); AuthenticationResponse response =newAuthenticationResponse(); response.setAuthenticated(xmlResponse.getStatus().equals( "AUTENTICADO" )); returnresponse; }catch(Throwable e) { throw newAuthenticationFailure(e); } } } 56. E depois?
- Refactor Clean Code
57. Coverage Test (Eclipse Emma) 58. Manter a cobertura dos testes em nvel elevado (acima de 90%) praticamente impossvel se voc no pratica Test First. 59. Aumentar a cobertura de cdigo Test After muito mais difcil, e pode dar um falsa sensao de cobertura. 60. Se der tempo...
- shouldNotAuthenticateInvalidUsername()
- RedGreenRefactor Coverage
ShouldNotAuthenticateInvalidPassword()
- RedGreenRefactor Coverage
shouldLogFailureOnAuthenticationErrors() 61. LoggingTests! 62. Logging Tests
- Como normalmente fazemos logging:
private static finalLoggerlogger= Logger.getLogger(Authenticator. class ); ... if( logger .isDebugEnabled()) logger .debug(message);
- Logging is a Feature: logging a User Interface do time de suporte!
63. Deve-se dar tanta importncia a testes de Logging como damos a testes de UI! 64. No desejvel que as mensagens crticas de logging quebrem com a evoluo da aplicao 65. Caso existam ferramentas automticas de anlise de log, elas iro quebrar caso o logging no seja estvel com o passar do tempo. 66. Mensagens de debbuging no precisam ser testadas. 67. Deve-se selecionar com critrio as mensagens crticas para a aplicao, que precisam ser testadas. 68. Tratar como Logging como Requisitos de Suporte? 69. Logging: Business Domain x Technical Domain
- possvel testar o arquivo de logging e verificar se as mensagens esperadas esto presentes.
70. Amarra a implementao biblioteca de Logging (mistura o domnio do negcio com o domnio tcnico). 71. Ports and Adapters strikes back
- Sugesto: Ports and Adapters Pattern.
- Authenticator interage com um delegate FailureReporter.
72. Testes de unidade verificam a relao entre Authenticator e FailureReporter 73. Testes de Integrao verificam a implementao do FailureReporter. 74. Logging com Ports e Adapters
- Bonus: permite a implementao de diferentes estratgias de FailureReporting
- Envio de Email, Persistncia / Estatsticas de falha, etc...
75. Dvidas?
- Obrigado!
top related