Your SlideShare is downloading. ×
0
TDD - Algumas lições aprendidas com o livro GOOS
TDD - Algumas lições aprendidas com o livro GOOS
TDD - Algumas lições aprendidas com o livro GOOS
TDD - Algumas lições aprendidas com o livro GOOS
TDD - Algumas lições aprendidas com o livro GOOS
TDD - Algumas lições aprendidas com o livro GOOS
TDD - Algumas lições aprendidas com o livro GOOS
TDD - Algumas lições aprendidas com o livro GOOS
TDD - Algumas lições aprendidas com o livro GOOS
TDD - Algumas lições aprendidas com o livro GOOS
TDD - Algumas lições aprendidas com o livro GOOS
TDD - Algumas lições aprendidas com o livro GOOS
TDD - Algumas lições aprendidas com o livro GOOS
TDD - Algumas lições aprendidas com o livro GOOS
TDD - Algumas lições aprendidas com o livro GOOS
TDD - Algumas lições aprendidas com o livro GOOS
TDD - Algumas lições aprendidas com o livro GOOS
TDD - Algumas lições aprendidas com o livro GOOS
TDD - Algumas lições aprendidas com o livro GOOS
TDD - Algumas lições aprendidas com o livro GOOS
TDD - Algumas lições aprendidas com o livro GOOS
TDD - Algumas lições aprendidas com o livro GOOS
TDD - Algumas lições aprendidas com o livro GOOS
TDD - Algumas lições aprendidas com o livro GOOS
TDD - Algumas lições aprendidas com o livro GOOS
TDD - Algumas lições aprendidas com o livro GOOS
Upcoming SlideShare
Loading in...5
×

Thanks for flagging this SlideShare!

Oops! An error has occurred.

×
Saving this for later? Get the SlideShare app to save on your phone or tablet. Read anywhere, anytime – even offline.
Text the download link to your phone
Standard text messaging rates apply

TDD - Algumas lições aprendidas com o livro GOOS

1,965

Published on

- TDD: Red – Green – Refactor …

- TDD: Red – Green – Refactor
- Testes de Unidade x Testes de Integração
- Ports and Adapters Pattern
- Business Domain versus Technical Domain
- Testes de Unidade com JMock
- Coverage Tests
- Logging Tests

Published in: Technology, Business
0 Comments
1 Like
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total Views
1,965
On Slideshare
0
From Embeds
0
Number of Embeds
1
Actions
Shares
0
Downloads
11
Comments
0
Likes
1
Embeds 0
No embeds

Report content
Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
No notes for slide

Transcript

  • 1. Test Driven Development <ul>Fábio Luiz Nery de Miranda baseado no livro Growing OO Software Guided by Tests </ul>
  • 2. Roadmap <ul><li>Problema: autenticação em um service provider de terceiros.
  • 3. TDD: Red – Green – Refactor
  • 4. Testes de Unidade x Testes de Integração
  • 5. Ports and Adapters Pattern </li><ul><li>(Business Domain versus Technical Domain) </li></ul><li>Testes de Unidade com JMock
  • 6. Coverage Tests
  • 7. Logging Tests </li></ul>
  • 8. Autenticação num Service Provider de Terceiros <ul><li>API REST / XML </li></ul>POST http://isp-authenticator.dev.globoi.com:8280/ws/rest/autenticacao XML Resquest Autenticação: <usuarioAutenticado> <glbId>303a6a6f616f646576406d61696c</glbId> <login>fulano</login> <senha>123456</senha> <ip>127.0.0.1</ip> </usuarioAutenticado> XML Response Autenticação <usuarioAutenticado> <emailPrincipal>fab1@spam.la</emailPrincipal> <glbId>12257993f74d2b1f</glbId> <login>fab1@spam.la</login> <status>AUTENTICADO</status> <statusUsuario>ATIVO</statusUsuario> <tipoUsuario>NAO_ASSINANTE</tipoUsuario> <usuarioID>21588993</usuarioID> </usuarioAutenticado>
  • 9. Por onde começar? <ul><li>Defina a classe de domínio que deseja testar (System Under Test – SUT)
  • 10. Queremos uma classe que realize autenticação (um Authenticator)
  • 11. O ponto de partida será AuthenticatorTests </li></ul>
  • 12. Qual o foco do teste? O nome do teste expressa a intenção? <ul><li>Defina o foco do teste, criando um método de teste cujo nome expresse a intenção </li><ul><li>(Ajuda a não se afastar do foco) </li></ul><li>Um Authenticator deve realizar autenticação caso o nome do usuário e a senha estejam corretos.
  • 13. @Test
  • 14. public void shouldAuthenticateWhenCredentialsAreValid() {
  • 15. } </li></ul>
  • 16. Exercitando o teste <ul><li>Comece a implementar o teste exercitando o SUT (mesmo que o SUT ainda não exista)
  • 17. @Test
  • 18. public void shouldAuthenticateWhenCredentialsAreValid() { </li><ul><ul><li>AuthenticationResponse response = authenticator.authenticate(validUsername, validPassword); </li></ul></ul><li>} </li></ul>
  • 19. Setup e Assertions <ul><li>Faça as asserções e o setup necessários.
  • 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() { </li><ul><ul><li>AuthenticationResponse response = authenticator.authenticate(validUsername, validPassword);
  • 25. assertThat(“authentication response”, response, is(notNullValue()));
  • 26. assertThat(“authentication response”, response.isAuthenticated(), is(true)); </li></ul></ul><li>} </li></ul>
  • 27. Implemente as classes do domínio (stubs vazios) <ul><li>Crie as classes, mas apenas o suficiente para desaparecerem os erros de compilação.
  • 28. Observe o teste falhar
  • 29. A mensagem de falha do teste expressa suficientemente bem o que está quebrado? </li></ul>
  • 30. A importância de falhar antes <ul><li>Evitar falsos positivos
  • 31. Promove boas práticas de diagnóstico de falhas (GOOS Best Practice!) </li><ul><li>A clareza nas mensagens de falha é muito importante
  • 32. Elas ajudarão a diagnosticar problemas, quando novas features provoquem quebra de código existente.
  • 33. A ausência de mensagens claras sobre a falha forçará o desenvolvedor a ter que ler e entender a implementação para saber o que quebrou (pior caso: quando o dev que fez quebrar o código não é o próprio autor do código) </li></ul><li>Hamcrest Library: matchers são “synthax sugar” e ajudam a criar mensagens de falha mais detalhadas. </li></ul>
  • 34. Implemente o código mais simples que permita o teste PASSAR <ul><li>Não precisa implementar toda a lógica complexa de uma só vez
  • 35. KISS – Keep It Simple
  • 36. Não perca o foco do teste.
  • 37. Não se distraia com premissas que devem ser validadas em outros testes. </li></ul>
  • 38. DONE? <ul><li>O que o Authenticator deveria fazer? </li><ul><li>POST num serviço REST/XML </li></ul><li>O que o Authenticator está fazendo? </li></ul>public AuthenticationResponse authenticate(String username, String password) throws AuthenticationFailure { return new AuthenticationResponse(); // lazy boy... } public class AuthenticationResponse { public Boolean isAuthenticated() { return true ; // aham... } } <ul><li>Authenticator é um fanfarrão... </li></ul>
  • 39. Pausa para Reflexão <ul><li>Authenticator deve se preocupar com os detalhes de como a autenticação é realizada?
  • 40. Resposta: Depende (nenhuma verdade é absoluta)
  • 41. Se está interessado em criar um Domain Model, é importante separar classes de domínio das classes que possuem detalhes técnicos de como a funcionalidade é implementada. </li></ul>
  • 42. Ports and Adapters Pattern <ul><li>Ports: interfaces p/ abstrair relações domínio x dependências externas)
  • 43. Adapters: implementam as interfaces, encapsulando o domínio técnico da aplicação
  • 44. Testes de Unidade: verificam o comportamento do Authenticator.
  • 45. Testes de Integração: verificam a implementação do delegate. </li></ul>
  • 46. Ports and Adapters Pattern (GOOS)
  • 47. Retornando foco ao teste... <ul><li>Queremos saber se o Authenticator comanda corretamente o delegate, sem se preocupar em como o delegate será implementado. </li></ul>private Mockery context = new Mockery(); private final Authenticator.Delegate delegate = context .mock(Authenticator.Delegate. class ); private Authenticator authenticator = new Authenticator( delegate ); @Test public void shouldAuthenticateSucessfully() throws Exception { context .checking( new Expectations() {{ AuthenticationResponse sucessfullAuthentication = new AuthenticationResponse(); sucessfullAuthentication.setAuthenticated( true ); oneOf( delegate ).performAuthentication(with( validUsername ), with( validPassword )); will( returnValue (sucessfullAuthentication)); }}); AuthenticationResponse response = authenticator .authenticate( validUsername , validPassword ); assertThat ( &quot;authentication response&quot; , response, is ( notNullValue ())); assertThat ( &quot;authentication response&quot; , response.isAuthenticated(), is ( true )); }
  • 48. Rodando os Testes... <ul><li>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 diagnóstico?
  • 50. Corrigir Authenticator e AuthenticationResponse e passar </li></ul>
  • 51. DONE? <ul><li>A classe Authenticator está coberta por testes de unidade.
  • 52. O Delegate responsável pela autenticação via POST/XML é injetado no Authenticator, via construtor.
  • 53. Resta prover uma implementação do Delegate – um RestTemplateDelegate, por exemplo – e escrever um teste de integração. </li></ul>
  • 54. Teste de Integração @RunWith (SpringJUnit4ClassRunner. class ) @ContextConfiguration (locations= &quot;classpath:beans.xml&quot; ) public class RestTemplateAuthenticatorTests { @Autowired private RestTemplateAuthenticationDelegate restTemplateDelegate ; private Authenticator authenticator ; @Before public void setup() { authenticator = new Authenticator( restTemplateDelegate ); } @Test public void authenticateUser() throws Exception { assertTrue ( authenticator .authenticate( &quot;fab1@spam.la&quot; , &quot;teste123456&quot; ).isAuthenticated()); }
  • 55. RestTemplateAutenticationDelegate public class RestTemplateAuthenticationDelegate implements Authenticator.Delegate { private final String url ; private final RestTemplate rest ; public RestTemplateAuthenticationDelegate(String url, RestTemplate rest) { this . url = url; this . rest = rest; } public AuthenticationResponse performAuthentication(String username, String password) throws AuthenticationFailure { try { XmlAuthenticationRequest xmlRequest = new XmlAuthenticationRequest(); xmlRequest.setIp( &quot;127.0.0.1&quot; ); xmlRequest.setLogin(username); xmlRequest.setSenha(password); XmlAuthenticationResponse xmlResponse = rest .postForObject( url , xmlRequest, XmlAuthenticationResponse. class ); AuthenticationResponse response = new AuthenticationResponse(); response.setAuthenticated(xmlResponse.getStatus().equals( &quot;AUTENTICADO&quot; )); return response; } catch (Throwable e) { throw new AuthenticationFailure(e); } } }
  • 56. E depois? <ul><li>Refactor – Clean Code
  • 57. Coverage Test (Eclipse Emma)
  • 58. Manter a cobertura dos testes em nível elevado (acima de 90%) é praticamente impossível se você não pratica Test First.
  • 59. Aumentar a cobertura de código “Test After” é muito mais difícil, e pode dar um falsa sensação de cobertura. </li></ul>
  • 60. Se der tempo... <ul><li>shouldNotAuthenticateInvalidUsername() </li><ul><li>Red – Green – Refactor – Coverage </li></ul><li>ShouldNotAuthenticateInvalidPassword() </li><ul><li>Red – Green – Refactor – Coverage </li></ul><li>shouldLogFailureOnAuthenticationErrors()
  • 61. LoggingTests! </li></ul>
  • 62. Logging Tests <ul><li>Como normalmente fazemos logging: </li></ul>private static final Logger logger = Logger.getLogger(Authenticator. class ); ... if ( logger .isDebugEnabled()) logger .debug(message); <ul><li>“ Logging is a Feature”: logging é a User Interface do time de suporte!
  • 63. Deve-se dar tanta importância a testes de Logging como damos a testes de UI!
  • 64. Não é desejável que as mensagens críticas de logging quebrem com a evolução da aplicação
  • 65. Caso existam ferramentas automáticas de análise de log, elas irão quebrar caso o logging não seja estável com o passar do tempo.
  • 66. Mensagens de debbuging não precisam ser testadas.
  • 67. Deve-se selecionar com critério as mensagens críticas para a aplicação, que precisam ser testadas.
  • 68. Tratar como Logging como Requisitos de Suporte? </li></ul>
  • 69. Logging: Business Domain x Technical Domain <ul><li>É possível testar o arquivo de logging e verificar se as mensagens esperadas estão presentes.
  • 70. Amarra a implementação à biblioteca de Logging (mistura o domínio do negócio com o domínio técnico). </li></ul>
  • 71. Ports and Adapters strikes back <ul><li>Sugestão: Ports and Adapters Pattern. </li><ul><li>Authenticator interage com um delegate FailureReporter.
  • 72. Testes de unidade verificam a relação entre Authenticator e FailureReporter
  • 73. Testes de Integração verificam a implementação do FailureReporter. </li></ul></ul>
  • 74. Logging com Ports e Adapters <ul><li>Bonus: permite a implementação de diferentes estratégias de FailureReporting </li><ul><li>Envio de Email, Persistência / Estatísticas de falha, etc... </li></ul></ul>
  • 75. Dúvidas? <ul>Obrigado! </ul>

×