Test Driven Development  [TDD] Christiano Milfont #XPCE 2009, Fortaleza Copyleft 2009 Milfont.org Desenvolvimento guiado a testes
Test Driven Development “ Desenvolvimento guiado por testes é um caminho de gerenciamento do medo durante a programação.” Kent Beck  -  Test Driven  Development by Example
Test Driven Development Standup Meeting @ 9h Pair Up Test First [Prática] Code Refactor Integrar ou Disponibilizar Ir para casa @ 17h
Test Driven Development O ritmo em 3 A’s Arrange [Criar um objeto] Act  [Invocar um método] Assert  [Verificar o resultado] Refactoring Workbook, Bill Wake
Test Driven Development RED - GREEN - REFACTOR Escreva um teste que não funciona. Escreva o código e faço-o funcionar. Refatore e elimine o código repetitivo.
Test Driven Development Red Bar Patterns One Step Test Starter Test Explanation Test Learning Test Another Test Regression Test Break Do Over
Test Driven Development Red Bar Patterns One Step Test Starter Test Explanation Test Learning Test Another Test Regression Test Break Do Over Issue issue = member . createIssue (name) .withType( type ) .withLevel( level ) .withSummary( summary ) .toProject( project );
Test Driven Development Red Bar Patterns One Step Test Starter Test Explanation Test Learning Test Another Test Regression Test Break Do Over @Test public void createIssueFromMember()  throws IllegalArgumentIssueException { member = new Member(); issue = member . createIssue ("Issue created"); Assert.assertNotNull( ISSUE_IN_NULL, issue); Assert.assertEquals( "State is not unconfirmed",  Status.UNCONFIRMED,  issue.getStatus()); }
Test Driven Development Red Bar Patterns One Step Test Starter Test Explanation Test Learning Test Another Test Regression Test Break Do Over issue =  new Member() . createIssue ("Issue created"); Assert. assertNotNull ( ISSUE_IN_NULL, issue); Assert. assertEquals ( "State is not unconfirmed",  Status.UNCONFIRMED,  issue.getStatus());
Test Driven Development Red Bar Patterns One Step Test Starter Test Explanation Test Learning Test Another Test Regression Test Break Do Over type = new Type(){{ this.setId(Long.valueOf(10)); this.setName(BUG); }}; member = new Member().withType(type); issue = member.getIssueInProgress(); Assert. assertNotNull (ISSUE_IN_NULL, issue); Assert. assertNotNull ("Type is null",  issue.getType()); Assert. assertTrue ("Type is not BUG",  issue.getType().getId() == type.getId()); Assert. assertTrue ("Type is not BUG", issue.getType().getName() == type.getName()); Assert. assertEquals ("Type is not BUG", issue.getType().getName(), BUG);
Test Driven Development Red Bar Patterns One Step Test Starter Test Explanation Test Learning Test Another Test Regression Test Break Do Over @Test public void  createIssueFromMemberWithNameEmpty () { ... } @Test public void  setTypeInIssueFromMember () throws IllegalArgumentIssueException { … }
Test Driven Development Red Bar Patterns One Step Test Starter Test Explanation Test Learning Test Another Test Regression Test Break Do Over Issue issue = member .createIssue(name) .withType( type ) .withLevel( level ) .withSummary( summary ) .toProject( project ); Assert.assertNotNull( "Issue não gerada com sucesso!", issue); Assert.assertTrue( "Issue não gerada e id não atribuído", issue.getId() > 0);
Test Driven Development Red Bar Patterns One Step Test Starter Test Explanation Test Learning Test Another Test Regression Test Break Do Over @Test public void  createIssueFromMemberWithNameNull() { try { issue =  new Member() .createIssue( null ); Assert.fail( "Didn't find expected exception of type " +  IllegalArgumentIssueException.class.getName()); }  catch (IllegalArgumentIssueException e) { Assert.assertEquals("Exception correctly catch",  "Name is null or empty“, e.getMessage()); } }
Test Driven Development Red Bar Patterns One Step Test Starter Test Explanation Test Learning Test Another Test Regression Test Break Do Over
Test Driven Development Green Bar Patterns Fake It (‘till you make it) Triangulate Obvious Implementation One to Many
Test Driven Development Green Bar Patterns Fake It (Till you make it) Triangulate Obvious Implementation One to Many context.checking(new Expectations() {{ oneOf (repository).persist(with(any(Issue.class))); will (new CustomAction("Add id value to issue") { public Object  invoke (Invocation invocation) throws Throwable { ( (Issue) invocation.getParameter(0)). setId(Long.valueOf(1)); return null; } });}});
Test Driven Development Green Bar Patterns Fake It (Till you make it) Triangulate Obvious Implementation One to Many @Test public void  setNullSummaryInIssueFromMember () {...} @Test public void  setSummaryInIssueFromMember () {...} @Test public void  setEmptySummaryInIssueFromMember () { ..}
Test Driven Development Green Bar Patterns Fake It (Till you make it) Triangulate Obvious Implementation One to Many ... List<Issue> issues = new ArrayList<Issue>() { { this.add( new Issue(Long.valueOf(134)) ); } }... Assert.assertTrue(“blable”, issues.size()==1);
Test Driven Development Green Bar Patterns Fake It (Till you make it) Triangulate Obvious Implementation One to Many ... List<Issue> issues = new ArrayList<Issue>() { { this.add( new Issue(Long.valueOf(134)) ); } }... Assert.assertTrue(“blable”,  issues.size()==1 );
Test Driven Development Testing Patterns Child Test Mock Object Self Shunt Log String Crash Test Dummy Broken Test Clean Check-In
Test Driven Development Testing Patterns Child Test Mock Object Self Shunt Log String Crash Test Dummy Broken Test Clean Check-In @RunWith(JMock.class) public class  LifeCycleOfIssueInProjectTest  { ... } @RunWith(JMock.class) public class  ReportIssuesTest   { ... }
Test Driven Development Testing Patterns Child Test Mock Object Self Shunt Log String Crash Test Dummy Broken Test Clean Check-In context.checking(new Expectations() {{ oneOf (repository).persist(with(any(Issue.class))); will (new CustomAction(&quot;Add id value to issue&quot;) { public Object  invoke (Invocation invocation) throws Throwable { ( (Issue) invocation.getParameter(0)). setId(Long.valueOf(1)); return null; } }); }});
Test Driven Development Testing Patterns Child Test Mock Object Self Shunt Log String Crash Test Dummy Broken Test Clean Check-In context.checking(new Expectations() {{ oneOf (repository).persist(with(any(Issue.class))); will (new CustomAction(&quot;Add id value to issue&quot;) { public Object  invoke (Invocation invocation) throws Throwable { ( (Issue) invocation.getParameter(0)). setId(Long.valueOf(1)); repository.issues.add( ( (Issue) invocation.getParameter(0))); return null; } }); }}); ... Assert.assertTrue( repository.size() == 12 );
Test Driven Development Testing Patterns Child Test Mock Object Self Shunt Log String Crash Test Dummy Broken Test Clean Check-In
Test Driven Development Testing Patterns Child Test Mock Object Self Shunt Log String Crash Test Dummy Broken Test Clean Check-In @Test public void  createIssueFromMemberWithNameNull() { try { issue =  new Member() .createIssue( null ); Assert. fail ( &quot;Didn't find expected exception of type &quot; +  IllegalArgumentIssueException.class.getName()); }  catch ( IllegalArgumentIssueException  e) { Assert.assertEquals(&quot; Exception correctly catch &quot;,  &quot; Name is null or empty “,  e.getMessage() ); } }
Test Driven Development Testing Patterns Child Test Mock Object Self Shunt Log String Crash Test Dummy Broken Test Clean Check-In
Test Driven Development Testing Patterns Child Test Mock Object Self Shunt Log String Crash Test Dummy Broken Test Clean Check-In
Test Driven Development Test Double Dummy Fake Stubs Spies Mocks
Test Driven Development Test Double Dummy Fake Stubs Spies Mocks ... List<Issue> issues = new ArrayList<Issue>() { { this.add( new Issue(Long.valueOf(134)) ); } }... Assert.assertTrue(“blable”, issues.size()==1);
Test Driven Development Test Double Dummy Fake Stubs Spies Mocks ... IssueRepository repository =  new FakeRepository(); List<Issue> issuesUnconfirmeds  = repository. getIssuesUnconfirmeds(); Assert.assertTrue(“blable”, issuesUnconfirmeds != null); ... public class FakeRepository implements IssueRepository { public List<Issue> getIssuesUnconfirmeds() { return new ArrayList<Issue>(); } }
Test Driven Development Test Double Dummy Fake Stubs Spies Mocks context.checking(new Expectations() {{ ignoring (repository).count(); will ( returnValue(42)); }}); ... Assert.assertEquals( 12 ,  repository.count() );
Test Driven Development Test Double Dummy Fake Stubs Spies Mocks context.checking(new Expectations() {{ oneOf (repository).persist(with(any(Issue.class))); will (new CustomAction(&quot;Add id value to issue&quot;) { public Object  invoke (Invocation invocation) throws Throwable { ( (Issue) invocation.getParameter(0)). setId(Long.valueOf(1)); repository.issues.add( ( (Issue) invocation.getParameter(0))); return null; } }); }}); ... Assert.assertTrue( repository.size() == 12 );
Test Driven Development Test Double Dummy Fake Stubs Spies Mocks context.checking(new Expectations() {{ oneOf (repository).persist(with(any(Issue.class))); will (new CustomAction(&quot;Add id value to issue&quot;) { public Object  invoke (Invocation invocation) throws Throwable { ( (Issue) invocation.getParameter(0)). setId(Long.valueOf(1)); return null; } }); }});
Test Driven Development Fixture Setup Setup Tear Down @Before public void setUp() throws Exception { Connection conn; try { ... IDatabaseConnection connection =  new DatabaseConnection(conn); DatabaseOperation.INSERT.execute(connection,  new FlatXmlDataSet( new FileInputStream(  “ issuetrackr.xml&quot;))); conn.close(); } catch (Exception exc) { ...  } }

Test Driven Development

  • 1.
    Test Driven Development [TDD] Christiano Milfont #XPCE 2009, Fortaleza Copyleft 2009 Milfont.org Desenvolvimento guiado a testes
  • 2.
    Test Driven Development“ Desenvolvimento guiado por testes é um caminho de gerenciamento do medo durante a programação.” Kent Beck - Test Driven Development by Example
  • 3.
    Test Driven DevelopmentStandup Meeting @ 9h Pair Up Test First [Prática] Code Refactor Integrar ou Disponibilizar Ir para casa @ 17h
  • 4.
    Test Driven DevelopmentO ritmo em 3 A’s Arrange [Criar um objeto] Act [Invocar um método] Assert [Verificar o resultado] Refactoring Workbook, Bill Wake
  • 5.
    Test Driven DevelopmentRED - GREEN - REFACTOR Escreva um teste que não funciona. Escreva o código e faço-o funcionar. Refatore e elimine o código repetitivo.
  • 6.
    Test Driven DevelopmentRed Bar Patterns One Step Test Starter Test Explanation Test Learning Test Another Test Regression Test Break Do Over
  • 7.
    Test Driven DevelopmentRed Bar Patterns One Step Test Starter Test Explanation Test Learning Test Another Test Regression Test Break Do Over Issue issue = member . createIssue (name) .withType( type ) .withLevel( level ) .withSummary( summary ) .toProject( project );
  • 8.
    Test Driven DevelopmentRed Bar Patterns One Step Test Starter Test Explanation Test Learning Test Another Test Regression Test Break Do Over @Test public void createIssueFromMember() throws IllegalArgumentIssueException { member = new Member(); issue = member . createIssue (&quot;Issue created&quot;); Assert.assertNotNull( ISSUE_IN_NULL, issue); Assert.assertEquals( &quot;State is not unconfirmed&quot;, Status.UNCONFIRMED, issue.getStatus()); }
  • 9.
    Test Driven DevelopmentRed Bar Patterns One Step Test Starter Test Explanation Test Learning Test Another Test Regression Test Break Do Over issue = new Member() . createIssue (&quot;Issue created&quot;); Assert. assertNotNull ( ISSUE_IN_NULL, issue); Assert. assertEquals ( &quot;State is not unconfirmed&quot;, Status.UNCONFIRMED, issue.getStatus());
  • 10.
    Test Driven DevelopmentRed Bar Patterns One Step Test Starter Test Explanation Test Learning Test Another Test Regression Test Break Do Over type = new Type(){{ this.setId(Long.valueOf(10)); this.setName(BUG); }}; member = new Member().withType(type); issue = member.getIssueInProgress(); Assert. assertNotNull (ISSUE_IN_NULL, issue); Assert. assertNotNull (&quot;Type is null&quot;, issue.getType()); Assert. assertTrue (&quot;Type is not BUG&quot;, issue.getType().getId() == type.getId()); Assert. assertTrue (&quot;Type is not BUG&quot;, issue.getType().getName() == type.getName()); Assert. assertEquals (&quot;Type is not BUG&quot;, issue.getType().getName(), BUG);
  • 11.
    Test Driven DevelopmentRed Bar Patterns One Step Test Starter Test Explanation Test Learning Test Another Test Regression Test Break Do Over @Test public void createIssueFromMemberWithNameEmpty () { ... } @Test public void setTypeInIssueFromMember () throws IllegalArgumentIssueException { … }
  • 12.
    Test Driven DevelopmentRed Bar Patterns One Step Test Starter Test Explanation Test Learning Test Another Test Regression Test Break Do Over Issue issue = member .createIssue(name) .withType( type ) .withLevel( level ) .withSummary( summary ) .toProject( project ); Assert.assertNotNull( &quot;Issue não gerada com sucesso!&quot;, issue); Assert.assertTrue( &quot;Issue não gerada e id não atribuído&quot;, issue.getId() > 0);
  • 13.
    Test Driven DevelopmentRed Bar Patterns One Step Test Starter Test Explanation Test Learning Test Another Test Regression Test Break Do Over @Test public void createIssueFromMemberWithNameNull() { try { issue = new Member() .createIssue( null ); Assert.fail( &quot;Didn't find expected exception of type &quot; + IllegalArgumentIssueException.class.getName()); } catch (IllegalArgumentIssueException e) { Assert.assertEquals(&quot;Exception correctly catch&quot;, &quot;Name is null or empty“, e.getMessage()); } }
  • 14.
    Test Driven DevelopmentRed Bar Patterns One Step Test Starter Test Explanation Test Learning Test Another Test Regression Test Break Do Over
  • 15.
    Test Driven DevelopmentGreen Bar Patterns Fake It (‘till you make it) Triangulate Obvious Implementation One to Many
  • 16.
    Test Driven DevelopmentGreen Bar Patterns Fake It (Till you make it) Triangulate Obvious Implementation One to Many context.checking(new Expectations() {{ oneOf (repository).persist(with(any(Issue.class))); will (new CustomAction(&quot;Add id value to issue&quot;) { public Object invoke (Invocation invocation) throws Throwable { ( (Issue) invocation.getParameter(0)). setId(Long.valueOf(1)); return null; } });}});
  • 17.
    Test Driven DevelopmentGreen Bar Patterns Fake It (Till you make it) Triangulate Obvious Implementation One to Many @Test public void setNullSummaryInIssueFromMember () {...} @Test public void setSummaryInIssueFromMember () {...} @Test public void setEmptySummaryInIssueFromMember () { ..}
  • 18.
    Test Driven DevelopmentGreen Bar Patterns Fake It (Till you make it) Triangulate Obvious Implementation One to Many ... List<Issue> issues = new ArrayList<Issue>() { { this.add( new Issue(Long.valueOf(134)) ); } }... Assert.assertTrue(“blable”, issues.size()==1);
  • 19.
    Test Driven DevelopmentGreen Bar Patterns Fake It (Till you make it) Triangulate Obvious Implementation One to Many ... List<Issue> issues = new ArrayList<Issue>() { { this.add( new Issue(Long.valueOf(134)) ); } }... Assert.assertTrue(“blable”, issues.size()==1 );
  • 20.
    Test Driven DevelopmentTesting Patterns Child Test Mock Object Self Shunt Log String Crash Test Dummy Broken Test Clean Check-In
  • 21.
    Test Driven DevelopmentTesting Patterns Child Test Mock Object Self Shunt Log String Crash Test Dummy Broken Test Clean Check-In @RunWith(JMock.class) public class LifeCycleOfIssueInProjectTest { ... } @RunWith(JMock.class) public class ReportIssuesTest { ... }
  • 22.
    Test Driven DevelopmentTesting Patterns Child Test Mock Object Self Shunt Log String Crash Test Dummy Broken Test Clean Check-In context.checking(new Expectations() {{ oneOf (repository).persist(with(any(Issue.class))); will (new CustomAction(&quot;Add id value to issue&quot;) { public Object invoke (Invocation invocation) throws Throwable { ( (Issue) invocation.getParameter(0)). setId(Long.valueOf(1)); return null; } }); }});
  • 23.
    Test Driven DevelopmentTesting Patterns Child Test Mock Object Self Shunt Log String Crash Test Dummy Broken Test Clean Check-In context.checking(new Expectations() {{ oneOf (repository).persist(with(any(Issue.class))); will (new CustomAction(&quot;Add id value to issue&quot;) { public Object invoke (Invocation invocation) throws Throwable { ( (Issue) invocation.getParameter(0)). setId(Long.valueOf(1)); repository.issues.add( ( (Issue) invocation.getParameter(0))); return null; } }); }}); ... Assert.assertTrue( repository.size() == 12 );
  • 24.
    Test Driven DevelopmentTesting Patterns Child Test Mock Object Self Shunt Log String Crash Test Dummy Broken Test Clean Check-In
  • 25.
    Test Driven DevelopmentTesting Patterns Child Test Mock Object Self Shunt Log String Crash Test Dummy Broken Test Clean Check-In @Test public void createIssueFromMemberWithNameNull() { try { issue = new Member() .createIssue( null ); Assert. fail ( &quot;Didn't find expected exception of type &quot; + IllegalArgumentIssueException.class.getName()); } catch ( IllegalArgumentIssueException e) { Assert.assertEquals(&quot; Exception correctly catch &quot;, &quot; Name is null or empty “, e.getMessage() ); } }
  • 26.
    Test Driven DevelopmentTesting Patterns Child Test Mock Object Self Shunt Log String Crash Test Dummy Broken Test Clean Check-In
  • 27.
    Test Driven DevelopmentTesting Patterns Child Test Mock Object Self Shunt Log String Crash Test Dummy Broken Test Clean Check-In
  • 28.
    Test Driven DevelopmentTest Double Dummy Fake Stubs Spies Mocks
  • 29.
    Test Driven DevelopmentTest Double Dummy Fake Stubs Spies Mocks ... List<Issue> issues = new ArrayList<Issue>() { { this.add( new Issue(Long.valueOf(134)) ); } }... Assert.assertTrue(“blable”, issues.size()==1);
  • 30.
    Test Driven DevelopmentTest Double Dummy Fake Stubs Spies Mocks ... IssueRepository repository = new FakeRepository(); List<Issue> issuesUnconfirmeds = repository. getIssuesUnconfirmeds(); Assert.assertTrue(“blable”, issuesUnconfirmeds != null); ... public class FakeRepository implements IssueRepository { public List<Issue> getIssuesUnconfirmeds() { return new ArrayList<Issue>(); } }
  • 31.
    Test Driven DevelopmentTest Double Dummy Fake Stubs Spies Mocks context.checking(new Expectations() {{ ignoring (repository).count(); will ( returnValue(42)); }}); ... Assert.assertEquals( 12 , repository.count() );
  • 32.
    Test Driven DevelopmentTest Double Dummy Fake Stubs Spies Mocks context.checking(new Expectations() {{ oneOf (repository).persist(with(any(Issue.class))); will (new CustomAction(&quot;Add id value to issue&quot;) { public Object invoke (Invocation invocation) throws Throwable { ( (Issue) invocation.getParameter(0)). setId(Long.valueOf(1)); repository.issues.add( ( (Issue) invocation.getParameter(0))); return null; } }); }}); ... Assert.assertTrue( repository.size() == 12 );
  • 33.
    Test Driven DevelopmentTest Double Dummy Fake Stubs Spies Mocks context.checking(new Expectations() {{ oneOf (repository).persist(with(any(Issue.class))); will (new CustomAction(&quot;Add id value to issue&quot;) { public Object invoke (Invocation invocation) throws Throwable { ( (Issue) invocation.getParameter(0)). setId(Long.valueOf(1)); return null; } }); }});
  • 34.
    Test Driven DevelopmentFixture Setup Setup Tear Down @Before public void setUp() throws Exception { Connection conn; try { ... IDatabaseConnection connection = new DatabaseConnection(conn); DatabaseOperation.INSERT.execute(connection, new FlatXmlDataSet( new FileInputStream( “ issuetrackr.xml&quot;))); conn.close(); } catch (Exception exc) { ... } }

Editor's Notes

  • #2 Necessidade rara de debugar Facilidade em capturar erros antes de irem para produção Economia no retrabalho Guiado a criar codigo altamente coeso e com baixo acomplamento, mais modularizado, extensivel e flexivel, portanto de fácil manutenção. Matematico processo de assertions e precondições [Design by contracts] Principio de pareto 80-20 80% das consequências advém de 20% das causas