SlideShare a Scribd company logo

GeeCON 2012 Bad Tests, Good Tests

Tomek Kaczanowski
Tomek Kaczanowski
Tomek KaczanowskiHuman at Whatever

Slides from my GeeCON 2012 presentation. Few were removed so I do not spoil the fun for those of you who plan to attend my talk on Confitura.

GeeCON 2012 Bad Tests, Good Tests

1 of 89
Download to read offline
Bad Tests, Good Tests

Tomek Kaczanowski
Tomek Kaczanowski

•   Developer
•   Team lead
•   Blogger
     • http://kaczanowscy.pl/tomek
•   Book author
     • http://practicalunittesting.com

•   Working at CodeWise (Krakow)
      ...we are hiring, wanna join us?
Before we begin

•   Most of the examples are real but:
      Obfuscated
             to protect the innocents
         Truncated
             imagine much more complex domain objects
•   Asking questions is allowed
      ...but being smarter than me is not ;)
A little bit of history
Before we begin

•   The tests were written in 2004-2006.
•   No automation, no CI.
•   Some tests do not compile.
•   In some tests you can read a comment that "WARNING:
    test requires the divide param to be set to 20" but the
    code is so ugly, that there is no way to inject this value.
•   Some test data are available in form of serialized objects
    (*.ser) that can not be currently deserialized, because
    the classes have changed.
•   The project is now in maintenance.

                           Courtesy of Bartosz http://twitter.com/#!/bocytko
We don't need no stinkin' asserts!
public void testAddChunks() {
      System.out.println("*************************************");
      System.out.println("testAddChunks() ... ");
      ChunkMap cm = new ChunkMap(3);
      cm.addChunk(new Chunk("chunk"));

     List testList = cm.getChunks("chunk",null);

     if (testList.isEmpty())
           fail("there should be at least one list!");
     Chunk chunk = cm.getActualChunk("chunk",null);
     if (chunk.getElements().isEmpty())
           fail("there should be at least one element!");
     if (cm.getFinalChunkNr() != 1)
           fail("there should be at least one chunk!");
     // iterate actual chunk
     for (Iterator it = chunk.getElements().iterator();
                             it.hasNext();) {
           Element element = (Element) it.next();
           System.out.println("Element: " + element);
     }
     showChunks(cm);
     System.out.println("testAddChunks() OK ");
}
Ad

Recommended

Sample Chapter of Practical Unit Testing with TestNG and Mockito
Sample Chapter of Practical Unit Testing with TestNG and MockitoSample Chapter of Practical Unit Testing with TestNG and Mockito
Sample Chapter of Practical Unit Testing with TestNG and MockitoTomek Kaczanowski
 
2013 DevFest Vienna - Bad Tests, Good Tests
2013 DevFest Vienna - Bad Tests, Good Tests2013 DevFest Vienna - Bad Tests, Good Tests
2013 DevFest Vienna - Bad Tests, Good TestsTomek Kaczanowski
 
JUnit Kung Fu: Getting More Out of Your Unit Tests
JUnit Kung Fu: Getting More Out of Your Unit TestsJUnit Kung Fu: Getting More Out of Your Unit Tests
JUnit Kung Fu: Getting More Out of Your Unit TestsJohn Ferguson Smart Limited
 
33rd Degree 2013, Bad Tests, Good Tests
33rd Degree 2013, Bad Tests, Good Tests33rd Degree 2013, Bad Tests, Good Tests
33rd Degree 2013, Bad Tests, Good TestsTomek Kaczanowski
 
JUnit & Mockito, first steps
JUnit & Mockito, first stepsJUnit & Mockito, first steps
JUnit & Mockito, first stepsRenato Primavera
 

More Related Content

What's hot

An introduction to Google test framework
An introduction to Google test frameworkAn introduction to Google test framework
An introduction to Google test frameworkAbner Chih Yi Huang
 
Understanding JavaScript Testing
Understanding JavaScript TestingUnderstanding JavaScript Testing
Understanding JavaScript Testingjeresig
 
JUnit- A Unit Testing Framework
JUnit- A Unit Testing FrameworkJUnit- A Unit Testing Framework
JUnit- A Unit Testing FrameworkOnkar Deshpande
 
Understanding JavaScript Testing
Understanding JavaScript TestingUnderstanding JavaScript Testing
Understanding JavaScript TestingKissy Team
 
xUnit Style Database Testing
xUnit Style Database TestingxUnit Style Database Testing
xUnit Style Database TestingChris Oldwood
 
Mocking in Java with Mockito
Mocking in Java with MockitoMocking in Java with Mockito
Mocking in Java with MockitoRichard Paul
 
Advanced junit and mockito
Advanced junit and mockitoAdvanced junit and mockito
Advanced junit and mockitoMathieu Carbou
 
C++ Unit Test with Google Testing Framework
C++ Unit Test with Google Testing FrameworkC++ Unit Test with Google Testing Framework
C++ Unit Test with Google Testing FrameworkHumberto Marchezi
 
Test driven development - JUnit basics and best practices
Test driven development - JUnit basics and best practicesTest driven development - JUnit basics and best practices
Test driven development - JUnit basics and best practicesNarendra Pathai
 
Unit testing best practices with JUnit
Unit testing best practices with JUnitUnit testing best practices with JUnit
Unit testing best practices with JUnitinTwentyEight Minutes
 
Unit testing with PHPUnit - there's life outside of TDD
Unit testing with PHPUnit - there's life outside of TDDUnit testing with PHPUnit - there's life outside of TDD
Unit testing with PHPUnit - there's life outside of TDDPaweł Michalik
 
Unit testing with Junit
Unit testing with JunitUnit testing with Junit
Unit testing with JunitValerio Maggio
 
Introduction to Unit Testing with PHPUnit
Introduction to Unit Testing with PHPUnitIntroduction to Unit Testing with PHPUnit
Introduction to Unit Testing with PHPUnitMichelangelo van Dam
 

What's hot (20)

Junit
JunitJunit
Junit
 
Junit
JunitJunit
Junit
 
Unit testing with java
Unit testing with javaUnit testing with java
Unit testing with java
 
Testing with Junit4
Testing with Junit4Testing with Junit4
Testing with Junit4
 
An introduction to Google test framework
An introduction to Google test frameworkAn introduction to Google test framework
An introduction to Google test framework
 
Understanding JavaScript Testing
Understanding JavaScript TestingUnderstanding JavaScript Testing
Understanding JavaScript Testing
 
JUnit- A Unit Testing Framework
JUnit- A Unit Testing FrameworkJUnit- A Unit Testing Framework
JUnit- A Unit Testing Framework
 
Understanding JavaScript Testing
Understanding JavaScript TestingUnderstanding JavaScript Testing
Understanding JavaScript Testing
 
xUnit Style Database Testing
xUnit Style Database TestingxUnit Style Database Testing
xUnit Style Database Testing
 
Mocking in Java with Mockito
Mocking in Java with MockitoMocking in Java with Mockito
Mocking in Java with Mockito
 
Advanced junit and mockito
Advanced junit and mockitoAdvanced junit and mockito
Advanced junit and mockito
 
C++ Unit Test with Google Testing Framework
C++ Unit Test with Google Testing FrameworkC++ Unit Test with Google Testing Framework
C++ Unit Test with Google Testing Framework
 
Junit and testNG
Junit and testNGJunit and testNG
Junit and testNG
 
Test driven development - JUnit basics and best practices
Test driven development - JUnit basics and best practicesTest driven development - JUnit basics and best practices
Test driven development - JUnit basics and best practices
 
JUNit Presentation
JUNit PresentationJUNit Presentation
JUNit Presentation
 
Unit testing with JUnit
Unit testing with JUnitUnit testing with JUnit
Unit testing with JUnit
 
Unit testing best practices with JUnit
Unit testing best practices with JUnitUnit testing best practices with JUnit
Unit testing best practices with JUnit
 
Unit testing with PHPUnit - there's life outside of TDD
Unit testing with PHPUnit - there's life outside of TDDUnit testing with PHPUnit - there's life outside of TDD
Unit testing with PHPUnit - there's life outside of TDD
 
Unit testing with Junit
Unit testing with JunitUnit testing with Junit
Unit testing with Junit
 
Introduction to Unit Testing with PHPUnit
Introduction to Unit Testing with PHPUnitIntroduction to Unit Testing with PHPUnit
Introduction to Unit Testing with PHPUnit
 

Similar to GeeCON 2012 Bad Tests, Good Tests

Confitura 2012 Bad Tests, Good Tests
Confitura 2012 Bad Tests, Good TestsConfitura 2012 Bad Tests, Good Tests
Confitura 2012 Bad Tests, Good TestsTomek Kaczanowski
 
2012 JDays Bad Tests Good Tests
2012 JDays Bad Tests Good Tests2012 JDays Bad Tests Good Tests
2012 JDays Bad Tests Good TestsTomek Kaczanowski
 
J unit presentation
J unit presentationJ unit presentation
J unit presentationPriya Sharma
 
How to Start Test-Driven Development in Legacy Code
How to Start Test-Driven Development in Legacy CodeHow to Start Test-Driven Development in Legacy Code
How to Start Test-Driven Development in Legacy CodeDaniel Wellman
 
How to write clean tests
How to write clean testsHow to write clean tests
How to write clean testsDanylenko Max
 
Junit4&testng presentation
Junit4&testng presentationJunit4&testng presentation
Junit4&testng presentationSanjib Dhar
 
PQTimer.java A simple driver program to run timing t.docx
  PQTimer.java     A simple driver program to run timing t.docx  PQTimer.java     A simple driver program to run timing t.docx
PQTimer.java A simple driver program to run timing t.docxjoyjonna282
 
Testing, Performance Analysis, and jQuery 1.4
Testing, Performance Analysis, and jQuery 1.4Testing, Performance Analysis, and jQuery 1.4
Testing, Performance Analysis, and jQuery 1.4jeresig
 
Pragmatic unittestingwithj unit
Pragmatic unittestingwithj unitPragmatic unittestingwithj unit
Pragmatic unittestingwithj unitliminescence
 
IN JAVA, 1. Put TestCalculator and UnlockTest in the default packa.pdf
IN JAVA, 1. Put TestCalculator and UnlockTest in the default packa.pdfIN JAVA, 1. Put TestCalculator and UnlockTest in the default packa.pdf
IN JAVA, 1. Put TestCalculator and UnlockTest in the default packa.pdfaggarwalenterprisesf
 
Developer Test - Things to Know
Developer Test - Things to KnowDeveloper Test - Things to Know
Developer Test - Things to Knowvilniusjug
 
Unit testing in iOS featuring OCUnit, GHUnit & OCMock
Unit testing in iOS featuring OCUnit, GHUnit & OCMockUnit testing in iOS featuring OCUnit, GHUnit & OCMock
Unit testing in iOS featuring OCUnit, GHUnit & OCMockRobot Media
 

Similar to GeeCON 2012 Bad Tests, Good Tests (20)

Confitura 2012 Bad Tests, Good Tests
Confitura 2012 Bad Tests, Good TestsConfitura 2012 Bad Tests, Good Tests
Confitura 2012 Bad Tests, Good Tests
 
2012 JDays Bad Tests Good Tests
2012 JDays Bad Tests Good Tests2012 JDays Bad Tests Good Tests
2012 JDays Bad Tests Good Tests
 
J unit presentation
J unit presentationJ unit presentation
J unit presentation
 
JUnit Presentation
JUnit PresentationJUnit Presentation
JUnit Presentation
 
How to Start Test-Driven Development in Legacy Code
How to Start Test-Driven Development in Legacy CodeHow to Start Test-Driven Development in Legacy Code
How to Start Test-Driven Development in Legacy Code
 
How to write clean tests
How to write clean testsHow to write clean tests
How to write clean tests
 
J Unit
J UnitJ Unit
J Unit
 
Junit4&testng presentation
Junit4&testng presentationJunit4&testng presentation
Junit4&testng presentation
 
Java programs
Java programsJava programs
Java programs
 
Junit With Eclipse
Junit With EclipseJunit With Eclipse
Junit With Eclipse
 
PQTimer.java A simple driver program to run timing t.docx
  PQTimer.java     A simple driver program to run timing t.docx  PQTimer.java     A simple driver program to run timing t.docx
PQTimer.java A simple driver program to run timing t.docx
 
Testing, Performance Analysis, and jQuery 1.4
Testing, Performance Analysis, and jQuery 1.4Testing, Performance Analysis, and jQuery 1.4
Testing, Performance Analysis, and jQuery 1.4
 
Pragmatic unittestingwithj unit
Pragmatic unittestingwithj unitPragmatic unittestingwithj unit
Pragmatic unittestingwithj unit
 
Presentation Unit Testing process
Presentation Unit Testing processPresentation Unit Testing process
Presentation Unit Testing process
 
IN JAVA, 1. Put TestCalculator and UnlockTest in the default packa.pdf
IN JAVA, 1. Put TestCalculator and UnlockTest in the default packa.pdfIN JAVA, 1. Put TestCalculator and UnlockTest in the default packa.pdf
IN JAVA, 1. Put TestCalculator and UnlockTest in the default packa.pdf
 
Developer Test - Things to Know
Developer Test - Things to KnowDeveloper Test - Things to Know
Developer Test - Things to Know
 
Unit testing in iOS featuring OCUnit, GHUnit & OCMock
Unit testing in iOS featuring OCUnit, GHUnit & OCMockUnit testing in iOS featuring OCUnit, GHUnit & OCMock
Unit testing in iOS featuring OCUnit, GHUnit & OCMock
 
TestNG vs Junit
TestNG vs JunitTestNG vs Junit
TestNG vs Junit
 
Good Tests Bad Tests
Good Tests Bad TestsGood Tests Bad Tests
Good Tests Bad Tests
 
Google guava
Google guavaGoogle guava
Google guava
 

More from Tomek Kaczanowski

Grupowe podejmowanie decyzji
Grupowe podejmowanie decyzjiGrupowe podejmowanie decyzji
Grupowe podejmowanie decyzjiTomek Kaczanowski
 
Practical Unit Testing with TestNG and Mockito
Practical Unit Testing with TestNG and MockitoPractical Unit Testing with TestNG and Mockito
Practical Unit Testing with TestNG and MockitoTomek Kaczanowski
 
GeeCON 2011 Who Watches The Watchmen? - On Quality Of Tests
GeeCON 2011 Who Watches The Watchmen? - On Quality Of TestsGeeCON 2011 Who Watches The Watchmen? - On Quality Of Tests
GeeCON 2011 Who Watches The Watchmen? - On Quality Of TestsTomek Kaczanowski
 
Convention Over Configuration - Maven 3, Polyglot Maven, Gradle and Ant
Convention Over Configuration - Maven 3, Polyglot Maven, Gradle and AntConvention Over Configuration - Maven 3, Polyglot Maven, Gradle and Ant
Convention Over Configuration - Maven 3, Polyglot Maven, Gradle and AntTomek Kaczanowski
 
Gradle talk, Javarsovia 2010
Gradle talk, Javarsovia 2010Gradle talk, Javarsovia 2010
Gradle talk, Javarsovia 2010Tomek Kaczanowski
 

More from Tomek Kaczanowski (6)

2015 ACE! Conference slides
2015 ACE! Conference slides2015 ACE! Conference slides
2015 ACE! Conference slides
 
Grupowe podejmowanie decyzji
Grupowe podejmowanie decyzjiGrupowe podejmowanie decyzji
Grupowe podejmowanie decyzji
 
Practical Unit Testing with TestNG and Mockito
Practical Unit Testing with TestNG and MockitoPractical Unit Testing with TestNG and Mockito
Practical Unit Testing with TestNG and Mockito
 
GeeCON 2011 Who Watches The Watchmen? - On Quality Of Tests
GeeCON 2011 Who Watches The Watchmen? - On Quality Of TestsGeeCON 2011 Who Watches The Watchmen? - On Quality Of Tests
GeeCON 2011 Who Watches The Watchmen? - On Quality Of Tests
 
Convention Over Configuration - Maven 3, Polyglot Maven, Gradle and Ant
Convention Over Configuration - Maven 3, Polyglot Maven, Gradle and AntConvention Over Configuration - Maven 3, Polyglot Maven, Gradle and Ant
Convention Over Configuration - Maven 3, Polyglot Maven, Gradle and Ant
 
Gradle talk, Javarsovia 2010
Gradle talk, Javarsovia 2010Gradle talk, Javarsovia 2010
Gradle talk, Javarsovia 2010
 

Recently uploaded

Microsoft Azure News - Feb 2024
Microsoft Azure News - Feb 2024Microsoft Azure News - Feb 2024
Microsoft Azure News - Feb 2024Daniel Toomey
 
My self introduction to know others abut me
My self  introduction to know others abut meMy self  introduction to know others abut me
My self introduction to know others abut meManoj Prabakar B
 
Journey of Television in World & in India
Journey of Television in World & in IndiaJourney of Television in World & in India
Journey of Television in World & in IndiaAdarshAgarwal66
 
Introduction to Serverless with AWS Lambda in C#.pptx
Introduction to Serverless with AWS Lambda in C#.pptxIntroduction to Serverless with AWS Lambda in C#.pptx
Introduction to Serverless with AWS Lambda in C#.pptxBrandon Minnick, MBA
 
My sample product research idea for you!
My sample product research idea for you!My sample product research idea for you!
My sample product research idea for you!KivenRaySarsaba
 
Put a flag on it. A busy developer's guide to feature toggles.
Put a flag on it. A busy developer's guide to feature toggles.Put a flag on it. A busy developer's guide to feature toggles.
Put a flag on it. A busy developer's guide to feature toggles.Mateusz Kwasniewski
 
Curtain Module Manual Zigbee Neo CS01-1C.pdf
Curtain Module Manual Zigbee Neo CS01-1C.pdfCurtain Module Manual Zigbee Neo CS01-1C.pdf
Curtain Module Manual Zigbee Neo CS01-1C.pdfDomotica daVinci
 
2) Presentation_Overview_ISO_16140-3_Method_verification_20210322.pptx
2) Presentation_Overview_ISO_16140-3_Method_verification_20210322.pptx2) Presentation_Overview_ISO_16140-3_Method_verification_20210322.pptx
2) Presentation_Overview_ISO_16140-3_Method_verification_20210322.pptxssuser796efb
 
2024 February Patch Tuesday
2024 February Patch Tuesday2024 February Patch Tuesday
2024 February Patch TuesdayIvanti
 
Q1 Memory Fabric Forum: XConn CXL Switches for AI
Q1 Memory Fabric Forum: XConn CXL Switches for AIQ1 Memory Fabric Forum: XConn CXL Switches for AI
Q1 Memory Fabric Forum: XConn CXL Switches for AIMemory Fabric Forum
 
Semiconductor Review Magazine Feature.pdf
Semiconductor Review Magazine Feature.pdfSemiconductor Review Magazine Feature.pdf
Semiconductor Review Magazine Feature.pdfkeyaramicrochipusa
 
Azure Migration Guide for IT Professionals
Azure Migration Guide for IT ProfessionalsAzure Migration Guide for IT Professionals
Azure Migration Guide for IT ProfessionalsChristine Shepherd
 
From eSIMs to iSIMs: It’s Inside the Manufacturing
From eSIMs to iSIMs: It’s Inside the ManufacturingFrom eSIMs to iSIMs: It’s Inside the Manufacturing
From eSIMs to iSIMs: It’s Inside the ManufacturingSoracom Global, Inc.
 
Dynamical systems simulation in Python for science and engineering
Dynamical systems simulation in Python for science and engineeringDynamical systems simulation in Python for science and engineering
Dynamical systems simulation in Python for science and engineeringMassimo Talia
 
Q1 Memory Fabric Forum: SMART CXL Product Lineup
Q1 Memory Fabric Forum: SMART CXL Product LineupQ1 Memory Fabric Forum: SMART CXL Product Lineup
Q1 Memory Fabric Forum: SMART CXL Product LineupMemory Fabric Forum
 
Bit N Build Poland
Bit N Build PolandBit N Build Poland
Bit N Build PolandGDSC PJATK
 
M.Aathiraju Self Intro.docx-AD21001_____
M.Aathiraju Self Intro.docx-AD21001_____M.Aathiraju Self Intro.docx-AD21001_____
M.Aathiraju Self Intro.docx-AD21001_____Aathiraju
 
Unlocking the Cloud's True Potential: Why Multitenancy Is The Key?
Unlocking the Cloud's True Potential: Why Multitenancy Is The Key?Unlocking the Cloud's True Potential: Why Multitenancy Is The Key?
Unlocking the Cloud's True Potential: Why Multitenancy Is The Key?GleecusTechlabs1
 

Recently uploaded (20)

Microsoft Azure News - Feb 2024
Microsoft Azure News - Feb 2024Microsoft Azure News - Feb 2024
Microsoft Azure News - Feb 2024
 
My self introduction to know others abut me
My self  introduction to know others abut meMy self  introduction to know others abut me
My self introduction to know others abut me
 
Journey of Television in World & in India
Journey of Television in World & in IndiaJourney of Television in World & in India
Journey of Television in World & in India
 
Introduction to Serverless with AWS Lambda in C#.pptx
Introduction to Serverless with AWS Lambda in C#.pptxIntroduction to Serverless with AWS Lambda in C#.pptx
Introduction to Serverless with AWS Lambda in C#.pptx
 
My sample product research idea for you!
My sample product research idea for you!My sample product research idea for you!
My sample product research idea for you!
 
Put a flag on it. A busy developer's guide to feature toggles.
Put a flag on it. A busy developer's guide to feature toggles.Put a flag on it. A busy developer's guide to feature toggles.
Put a flag on it. A busy developer's guide to feature toggles.
 
Curtain Module Manual Zigbee Neo CS01-1C.pdf
Curtain Module Manual Zigbee Neo CS01-1C.pdfCurtain Module Manual Zigbee Neo CS01-1C.pdf
Curtain Module Manual Zigbee Neo CS01-1C.pdf
 
2) Presentation_Overview_ISO_16140-3_Method_verification_20210322.pptx
2) Presentation_Overview_ISO_16140-3_Method_verification_20210322.pptx2) Presentation_Overview_ISO_16140-3_Method_verification_20210322.pptx
2) Presentation_Overview_ISO_16140-3_Method_verification_20210322.pptx
 
2024 February Patch Tuesday
2024 February Patch Tuesday2024 February Patch Tuesday
2024 February Patch Tuesday
 
Q1 Memory Fabric Forum: XConn CXL Switches for AI
Q1 Memory Fabric Forum: XConn CXL Switches for AIQ1 Memory Fabric Forum: XConn CXL Switches for AI
Q1 Memory Fabric Forum: XConn CXL Switches for AI
 
Semiconductor Review Magazine Feature.pdf
Semiconductor Review Magazine Feature.pdfSemiconductor Review Magazine Feature.pdf
Semiconductor Review Magazine Feature.pdf
 
5 Tech Trend to Notice in ESG Landscape- 47Billion
5 Tech Trend to Notice in ESG Landscape- 47Billion5 Tech Trend to Notice in ESG Landscape- 47Billion
5 Tech Trend to Notice in ESG Landscape- 47Billion
 
Azure Migration Guide for IT Professionals
Azure Migration Guide for IT ProfessionalsAzure Migration Guide for IT Professionals
Azure Migration Guide for IT Professionals
 
From eSIMs to iSIMs: It’s Inside the Manufacturing
From eSIMs to iSIMs: It’s Inside the ManufacturingFrom eSIMs to iSIMs: It’s Inside the Manufacturing
From eSIMs to iSIMs: It’s Inside the Manufacturing
 
Dynamical systems simulation in Python for science and engineering
Dynamical systems simulation in Python for science and engineeringDynamical systems simulation in Python for science and engineering
Dynamical systems simulation in Python for science and engineering
 
Q1 Memory Fabric Forum: SMART CXL Product Lineup
Q1 Memory Fabric Forum: SMART CXL Product LineupQ1 Memory Fabric Forum: SMART CXL Product Lineup
Q1 Memory Fabric Forum: SMART CXL Product Lineup
 
Bit N Build Poland
Bit N Build PolandBit N Build Poland
Bit N Build Poland
 
COE AI Lab Universities
COE AI Lab UniversitiesCOE AI Lab Universities
COE AI Lab Universities
 
M.Aathiraju Self Intro.docx-AD21001_____
M.Aathiraju Self Intro.docx-AD21001_____M.Aathiraju Self Intro.docx-AD21001_____
M.Aathiraju Self Intro.docx-AD21001_____
 
Unlocking the Cloud's True Potential: Why Multitenancy Is The Key?
Unlocking the Cloud's True Potential: Why Multitenancy Is The Key?Unlocking the Cloud's True Potential: Why Multitenancy Is The Key?
Unlocking the Cloud's True Potential: Why Multitenancy Is The Key?
 

GeeCON 2012 Bad Tests, Good Tests

  • 1. Bad Tests, Good Tests Tomek Kaczanowski
  • 2. Tomek Kaczanowski • Developer • Team lead • Blogger • http://kaczanowscy.pl/tomek • Book author • http://practicalunittesting.com • Working at CodeWise (Krakow)  ...we are hiring, wanna join us?
  • 3. Before we begin • Most of the examples are real but:  Obfuscated  to protect the innocents  Truncated  imagine much more complex domain objects • Asking questions is allowed  ...but being smarter than me is not ;)
  • 4. A little bit of history
  • 5. Before we begin • The tests were written in 2004-2006. • No automation, no CI. • Some tests do not compile. • In some tests you can read a comment that "WARNING: test requires the divide param to be set to 20" but the code is so ugly, that there is no way to inject this value. • Some test data are available in form of serialized objects (*.ser) that can not be currently deserialized, because the classes have changed. • The project is now in maintenance. Courtesy of Bartosz http://twitter.com/#!/bocytko
  • 6. We don't need no stinkin' asserts! public void testAddChunks() { System.out.println("*************************************"); System.out.println("testAddChunks() ... "); ChunkMap cm = new ChunkMap(3); cm.addChunk(new Chunk("chunk")); List testList = cm.getChunks("chunk",null); if (testList.isEmpty()) fail("there should be at least one list!"); Chunk chunk = cm.getActualChunk("chunk",null); if (chunk.getElements().isEmpty()) fail("there should be at least one element!"); if (cm.getFinalChunkNr() != 1) fail("there should be at least one chunk!"); // iterate actual chunk for (Iterator it = chunk.getElements().iterator(); it.hasNext();) { Element element = (Element) it.next(); System.out.println("Element: " + element); } showChunks(cm); System.out.println("testAddChunks() OK "); }
  • 7. Success is not an option... /** * Method testFailure. */ public void testFailure() { try { Message message = new Message(null,true); fail(); } catch(Exception ex) { ExceptionHandler.log(ExceptionLevel.ANY,ex); fail(); } }
  • 8. What has happened? Well, it failed... public void testSimple() { IData data = null; IFormat format = null; LinkedList<String> attr = new LinkedList<String>(); attr.add("A"); attr.add("B"); try { format = new SimpleFormat("A"); data.setAmount(Amount.TEN); data.setAttributes(attr); IResult result = format.execute(); System.out.println(result.size()); Iterator iter = result.iterator(); while (iter.hasNext()) { IResult r = (IResult) iter.next(); System.out.println(r.getMessage()); ... } } catch (Exception e) { fail(); } }
  • 9. What has happened? Well, it failed... public void testSimple() { IData data = null; IFormat format = null; LinkedList<String> attr = new LinkedList<String>(); attr.add("A"); attr.add("B"); data is still null here. Ready or not, NPE is coming. try { format = new SimpleFormat("A"); data.setAmount(Amount.TEN); data.setAttributes(attr); IResult result = format.execute(); System.out.println(result.size()); Iterator iter = result.iterator(); while (iter.hasNext()) { IResult r = (IResult) iter.next(); System.out.println(r.getMessage()); ... } } catch (Exception e) { fail(); } }
  • 10. Talk to me //wait for messages do { input = ""; try { System.out.print(">"); read = System.in.read(buf); //convert characters to string input = new String(buf, 0, read - newline.length()); System.out.println(input); if (input.equals("end") || input.equals("exit") || input.equals("stop") || input.equals("quit")) { System.out.println("Terminating Test please wait..."); System.out.println("******* Test terminated *******"); toStop = true; } else { System.out.println("Commands:" + newline + "'end', 'exit', 'stop' or 'quit' terminates this test "); } } catch (Exception e) { e.printStackTrace(); } } while (!toStop);
  • 11. Tests are boring – let us autogenerate them! /** protected void tearDown() throws Exception { * Generated by JUnitDoclet, a tool provided by // JUnitDoclet begin method testcase.tearDown * ObjectFab GmbH under LGPL. adapter = null; * Please see www.junitdoclet.org, www.gnu.org super.tearDown(); * and www.objectfab.de for informations about // JUnitDoclet end method testcase.tearDown * the tool, the licence and the authors. */ public void testMain() throws Exception { public class AdapterTest // JUnitDoclet begin method testMain // JUnitDoclet begin extends_implements Adapter.main(new String [] {"ADAPTER"}); extends TestCase // JUnitDoclet end method testMain // JUnitDoclet end extends_implements } { // JUnitDoclet begin class Adapter adapter = null; /** // JUnitDoclet end class * JUnitDoclet moves marker to this method, if there is not match * for them in the regenerated code and if the marker is not empty. public AdapterTest(String name) { * This way, no test gets lost when regenerating after renaming. // JUnitDoclet begin method AdapterTest * Method testVault is supposed to be empty. super(name); */ // JUnitDoclet end method AdapterTest public void testVault() throws Exception { } // JUnitDoclet begin method testcase.testVault // JUnitDoclet end method testcase.testVault public Adapter createInstance() throws Exception { } // JUnitDoclet begin method testcase.createInstance return new Adapter(); public static void main(String[] args) { // JUnitDoclet end method testcase.createInstance // JUnitDoclet begin method testcase.main } junit.textui.TestRunner.run(AdapterTest.class); // JUnitDoclet end method testcase.main protected void setUp() throws Exception { } // JUnitDoclet begin method testcase.setUp } super.setUp(); adapter = createInstance(); // JUnitDoclet end method testcase.setUp }
  • 12. Tests are boring – let us autogenerate them! public void testSetGetTimestamp() throws Exception { // JUnitDoclet begin method setTimestamp getTimestamp java.util.Calendar[] tests = {new GregorianCalendar(), null}; for (int i = 0; i < tests.length; i++) { adapter.setTimestamp(tests[i]); assertEquals(tests[i], adapter.getTimestamp()); } // JUnitDoclet end method setTimestamp getTimestamp } public void testSetGetParam() throws Exception { // JUnitDoclet begin method setParam getParam String[] tests = {"a", "aaa", "---", "23121313", "", null}; for (int i = 0; i < tests.length; i++) { adapter.setParam(tests[i]); assertEquals(tests[i], adapter.getParam()); } // JUnitDoclet end method setParam getParam }
  • 13. Conclusions • Automation! • Running • Verification • Tests are to be written not generated • You should be informed why your test failed • Master your tools  …at least learn the basics!
  • 15. Why bother with tests? • System works as expected • Changes do not hurt • Documentation http://twitter.com/#!/devops_borat
  • 16. Tests help to achieve quality Not sure when I saw this picture – probably in GOOS?
  • 17. What happens if we do it wrong? • Angry clients • Depressed developers http://www.joshcanhelp.com
  • 18. When I started out with unit tests, I was enthralled with the promise of ease and security that they would bring to my projects. In practice, however, the theory of sustainable software through unit tests started to break down. This difficulty continued to build up, until I finally threw my head back in anger and declared that "Unit Tests have become more trouble than they are worth." Llewellyn Falco and Michael Kennedy, Develop Mentor August 09
  • 20. The worst kind of tests
  • 21. No smoke without tests class SystemAdminSmokeTest extends GroovyTestCase { void testSmoke() { // do not remove below code // def ds = new org.h2.jdbcx.JdbcDataSource( // URL: 'jdbc:h2:mem:test;DB_CLOSE_DELAY=-1;MODE=Oracle', // user: 'sa', password: '') // // def jpaProperties = new Properties() // jpaProperties.setProperty( // 'hibernate.cache.use_second_level_cache', 'false') // jpaProperties.setProperty( // 'hibernate.cache.use_query_cache', 'false') // // def emf = new LocalContainerEntityManagerFactoryBean( // dataSource: ds, persistenceUnitName: 'my-domain', // jpaVendorAdapter: new HibernateJpaVendorAdapter( // database: Database.H2, showSql: true, // generateDdl: true), jpaProperties: jpaProperties) // some more code below, all commented out :( }
  • 22. Let's follow the leader! @Test public class ExampleTest { public void testExample() { assertTrue(true); } }
  • 23. Uh-oh, I feel lonely... @Test public class ExampleTest { public void testExample() { assertTrue(true); } }
  • 25. Asking for troubles... LoggingPropertyConfigurator configurator = mock(LoggingPropertyConfigurator.class); BaseServletContextListener baseServletContextListener = new BaseServletContextListener(configurator); Should load some @Test public void shouldLoadConfigProperties() { default config baseServletContextListener.contextInitialized(); verify(configurator).configure(any(Properties.class)); } @Test(expected = LoggingInitialisationException.class) Should load this public void shouldThrowLoggingException() { specific file System.setProperty("logConfig", "nonExistingFile"); baseServletContextListener.contextInitialized(); }
  • 27. Mock'em All! public String getUrl(User user, String timestamp) { String name=user.getFullName(); String url=baseUrl +"name="+URLEncoder.encode(name, "UTF-8") +"&timestamp="+timestamp; return url; } public String getUrl(User user) { Date date=new Date(); Long time=(date.getTime()/1000); //convert ms to seconds String timestamp=time.toString(); return getUrl(user, timestamp); }
  • 28. Mock'em All! public String getUrl(User user, String timestamp) { String name=user.getFullName(); String url=baseUrl +"name="+URLEncoder.encode(name, "UTF-8") +"&timestamp="+timestamp; return url; } public String getUrl(User user) { Date date=new Date(); Long time=(date.getTime()/1000); //convert ms to seconds String timestamp=time.toString(); return getUrl(user, timestamp); } @Test public void shouldUseTimestampMethod() { //given Util spyUtil = spy(util); //when spyUtil.getUrl(user); //then verify(spyUtil).getUrl(eq(user), anyString()); }
  • 29. Use the front door @Test public void shouldAddTimestampToGeneratedUrl() { //given util = new .... TimeProvider timeProvider = mock(TimeProvider.class); when(timeProvider.getTime()).thenReturn("12345"); util.set(timeProvider); //when String url = util.getUrl(user); //then assertThat(url).contains("timestamp=12345"); }
  • 30. Mock'em All! @Test public void shouldAddTimeZoneToModelAndView() { //given UserFacade userFacade = mock(UserFacade.class); ModelAndView modelAndView = mock(ModelAndView.class); given(userFacade.getTimezone()).willReturn("timezone X"); //when new UserDataInterceptor(userFacade) .postHandle(null, null, null, modelAndView); //then verify(modelAndView).addObject("timezone", "timezone X"); }
  • 31. Use the front door @Test public void shouldAddTimeZoneToModelAndView() { //given UserFacade userFacade = mock(UserFacade.class); ModelAndView modelAndView = new ModelAndView(); given(userFacade.getTimezone()).willReturn("timezone X"); //when new UserDataInterceptor(userFacade) .postHandle(null, null, null, modelAndView); //then assertThat(modelAndView).constains("timezone", "timezone X"); }
  • 33. SRP for tests A test should have one and only one reason to fail.
  • 34. Testing two things at once @DataProvider public Object[][] data() { return new Object[][] { {"48", true}, {"+48", true}, {"++48", true}, {"+48503", true}, {"+4", false}, {"++4", false}, {"", false}, {null, false}, {" ", false}, }; } @Test(dataProvider = "data") public void testQueryVerification(String query, boolean expected) { assertEquals(expected, FieldVerifier.isValidQuery(query)); }
  • 35. Testing two things at once @DataProvider public Object[][] data() { return new Object[][] { {"48", true}, {"+48", true}, Data {"++48", true}, {"+48503", true}, {"+4", false}, {"++4", false}, {"", false}, {null, false}, {" ", false}, }; } @Test(dataProvider = "data") Algorithm / Logic public void testQueryVerification(String query, boolean expected) { assertEquals(expected, FieldVerifier.isValidQuery(query)); }
  • 36. Testing two things at once @DataProvider public Object[][] data() { return new Object[][] { {"48", true}, {"+48", true}, {"++48", true}, {"+48503", true}, {"+4", false}, {"++4", false}, {"", false}, {null, false}, {" ", false}, }; } @Test(dataProvider = "data") public void testQueryVerification(String query, boolean expected) { assertEquals(expected, FieldVerifier.isValidQuery(query)); } testQueryVerification1() { assertEquals(true, FieldVerifier.isValidQuery(„48”)); } testQueryVerification2() { assertEquals(true, FieldVerifier.isValidQuery(„+48”)); } testQueryVerification3() { assertEquals(true, FieldVerifier.isValidQuery(„++48”)); } testQueryVerification4() { assertEquals(true, FieldVerifier.isValidQuery(„+48503”)); } ...
  • 37. Testing two things at once @DataProvider public Object[][] data() { return new Object[][] { {"48", true}, {"+48", true}, {"++48", true}, {"+48503", true}, {"+4", false}, {"++4", false}, {"", false}, {null, false}, {" ", false}, }; } @Test(dataProvider = "data") public void testQueryVerification(String query, boolean expected) { assertEquals(expected, FieldVerifier.isValidQuery(query)); }
  • 38. Concentrate on one feature @DataProvider public Object[][] validQueries() { return new Object[][] { {"48"}, {"48123"}, {"+48"}, {"++48"}, {"+48503"}}; } @Test(dataProvider = "validQueries") public void shouldRecognizeValidQueries( String validQuery) { assertTrue(FieldVerifier.isValidQuery(validQuery)); } @DataProvider public Object[][] invalidQueries() { return new Object[][] { {"+4"}, {"++4"}, {""}, {null}, {" "} }; } @Test(dataProvider = "invalidQueries") public void shouldRejectInvalidQueries( String invalidQuery) { assertFalse(FieldVerifier.isValidQuery(invalidQuery)); }
  • 40. Happy path testSum() { assertEquals(Math.sum(2,2), 4); } http://mw2.google.com/mw-panoramio/photos/medium/68775332.jpg
  • 41. Happy paths are for wimps 2 + 2 2 + -2 2 + -5 0 + 2 2 + 0 Integer.MAX_VALUE + something etc. http://kidskidskids.tumblr.com/post/1145294997
  • 42. Avoiding happy paths Start with one: testSum() { assertEquals(Math.sum(2,2), 4); } Do the simplest thing that works: sum(int x, int y) { return 4; } And then listen to your code. Because it tells you something. http://kidskidskids.tumblr.com/post/1145294997
  • 43. Avoiding happy paths sum(int x, int y) { return 4; } You moron! Your test is so pathetic, that I can make it pass by doing such a silly thing. Try harder! http://looneytunes09.files.wordpress.com/2010/07/lisa-yell.gif
  • 45. Who the heck is “user_2” ? @DataProvider public static Object[][] usersPermissions() { return new Object[][]{ {"user_1", Permission.READ}, {"user_1", Permission.WRITE}, {"user_1", Permission.REMOVE}, {"user_2", Permission.WRITE}, {"user_2", Permission.READ}, {"user_3", Permission.READ} }; }
  • 46. Ah, logged user can read and write... @DataProvider public static Object[][] usersPermissions() { return new Object[][]{ {ADMIN, Permission.READ}, {ADMIN, Permission.WRITE}, {ADMIN, Permission.REMOVE}, {LOGGED, Permission.WRITE}, {LOGGED, Permission.READ}, {GUEST, Permission.READ} }; }
  • 47. Do not make me learn the API! server = new MockServer(responseMap, true, new URL(SERVER_ROOT).getPort(), false);
  • 48. Do not make me learn the API! server = new MockServer(responseMap, true, new URL(SERVER_ROOT).getPort(), false); private static final boolean RESPONSE_IS_A_FILE = true; private static final boolean NO_SSL = false; server = new MockServer(responseMap, RESPONSE_IS_A_FILE, new URL(SERVER_ROOT).getPort(), NO_SSL);
  • 49. Do not make me learn the API! server = new MockServer(responseMap, true, new URL(SERVER_ROOT).getPort(), false); server = new MockServerBuilder() .withResponse(responseMap) .withResponseType(FILE) .withUrl(SERVER_ROOT) .withoutSsl().create();
  • 50. What is really important?
  • 51. What is really important? @DataProvider public Object[][] snapshotArtifacts() { return new Object[][]{ {"a", "b", "2.2-SNAPSHOT", Artifact.JAR }, {"c", "d", "2.2.4.6-SNAPSHOT", Artifact.JAR}, {"e", "f", "2-SNAPSHOT", Artifact.JAR} }; } @Test(dataProvider = "snapshotArtifacts") public void shouldRecognizeSnapshots( String groupId, String artifactId, String version, Type type) { Artifact artifact = new Artifact(groupId, artifactId, version, type); assertThat(artifact.isSnapshot()).isTrue(); }
  • 52. Only version matters @DataProvider public Object[][] snapshotVersions() { return new Object[][]{ {"2.2-SNAPSHOT"}, {"2.2.4.6-SNAPSHOT"}, {"2-SNAPSHOT"} }; } @Test(dataProvider = "snapshotVersions") public void shouldRecognizeSnapshots(String version) { Artifact artifact = new Artifact(VALID_GROUP, VALID_ARTIFACT_ID, version, VALID_TYPE); assertThat(artifact.isSnapshot()).isTrue(); }
  • 54. Test methods names are important • testFindTransactionsToAutoCharge() • testSystemSuccess() • testOperation()
  • 55. Test methods names are important • testFindTransactionsToAutoCharge() • testSystemSuccess() • testOperation() @Test public void testOperation() { configureRequest("/validate") rc = new RequestContext(parser, request) assert rc.getConnector() == null assert rc.getOperation().equals("validate") }
  • 56. “should” is better than “test” • testOperation() • testQuery() • testConstructor() • testFindUsersWithFilter() • shouldRejectInvalidRequests() • shouldSaveNewUserToDatabase() • constructorShouldFailWithNegativePrice() • shouldReturnOnlyUsersWithGivenName()
  • 57. “should” is better than “test” • Starting test method names with “should” steers you in the right direction. http://jochopra.blogspot.com/ • “test” prefix makes your test method a limitless bag where you throw everything worth testing http://www.greenerideal.com/
  • 58. Test methods names are important @Test public void testQuery(){ when(q.getResultList()).thenReturn(null); assertNull(dao.findByQuery(Transaction.class, q, false)); assertNull(dao.findByQuery(Operator.class, q, false)); assertNull(dao.findByQuery(null, null, false)); List result = new LinkedList(); when(q.getResultList()).thenReturn(result); assertEquals(dao.findByQuery(Transaction.class, q, false), result); assertEquals(dao.findByQuery(Operator.class, q, false), result); assertEquals(dao.findByQuery(null, null, false), null); when(q.getSingleResult()).thenReturn(null); assertEquals(dao.findByQuery(Transaction.class, q, true).size(), 0); assertEquals(dao.findByQuery(Operator.class, q, true).size(), 0); assertEquals(dao.findByQuery(null, null, true), null); when(q.getSingleResult()).thenReturn(t); assertSame(dao.findByQuery(Transaction.class, q, true).get(0), t); when(q.getSingleResult()).thenReturn(o); assertSame(dao.findByQuery(Operator.class, q, true).get(0), o); when(q.getSingleResult()).thenReturn(null); assertSame(dao.findByQuery(null, null, true), null); }
  • 60. Asserting using private methods @Test public void testChargeInRetryingState() throws Exception { // given TxDTO request = createTxDTO(RequestType.CHARGE); AndroidTransaction androidTransaction = ... // when final TxDTO txDTO = processor.processRequest(request); // then assertState(request, androidTransaction, CHARGED, CHARGE_PENDING, AS_ANDROID_TX_STATE, ClientMessage.SUCCESS, ResultCode.SUCCESS); }
  • 61. Matchers vs. private methods assertState(TxDTO txDTO, AndroidTransaction androidTransaction, AndroidTransactionState expectedAndroidState, AndroidTransactionState expectedPreviousAndroidState, ExtendedState expectedState, String expectedClientStatus, ResultCode expectedRequestResultCode) { final List<AndroidTransactionStep> steps = new ArrayList<>(androidTransaction.getTransactionSteps()); final boolean checkPreviousStep = expectedAndroidState != null; assertTrue(steps.size() >= (checkPreviousStep ? 3 : 2)); if (checkPreviousStep) { AndroidTransactionStep lastStep = steps.get(steps.size() - 2); assertEquals(lastStep.getTransactionState(), expectedPreviousAndroidState); } final AndroidTransactionStep lastStep = steps.get(steps.size() - 1); assertEquals(lastStep.getTransactionState(), expectedAndroidState); assertEquals(lastStep.getMessage(), expectedClientStatus); assertEquals(txDTO.getResultCode(), expectedRequestResultCode); assertEquals(androidTransaction.getState(), expectedAndroidState); assertEquals(androidTransaction.getExtendedState(), expectedState); if (expectedClientStatus == null) { verifyZeroInteractions(client); } }
  • 62. Matchers vs. private methods @Test public void testChargeInRetryingState() throws Exception { // given TxDTO request = createTxDTO(CHARGE); AndroidTransaction androidTransaction = ... // when final TxDTO txDTO = processor.processRequest(request); // then assertThat(androidTransaction).hasState(CHARGED) .hasMessage(ClientMessage.SUCCESS) .hasPreviousState(CHARGE_PENDING) .hasExtendedState(null); assertEquals(txDTO.getResultCode(), ResultCode.SUCCESS); }
  • 63. Assertion part is freaking huge public void shouldPreDeployApplication() { // given Artifact artifact = mock(Artifact.class); when(artifact.getFileName()).thenReturn("war-artifact-2.0.war"); ServerConfiguration config = new ServerConfiguration(ADDRESS, USER, KEY_FILE, TOMCAT_PATH, TEMP_PATH); Tomcat tomcat = new Tomcat(HTTP_TOMCAT_URL, config); String destDir = new File(".").getCanonicalPath() + SLASH + "target" + SLASH; new File(destDir).mkdirs(); // when tomcat.preDeploy(artifact, new FakeWar(WAR_FILE_LENGTH)); //then JSch jsch = new JSch(); jsch.addIdentity(KEY_FILE); Session session = jsch.getSession(USER, ADDRESS, 22); session.setConfig("StrictHostKeyChecking", "no"); session.connect(); Channel channel = session.openChannel("sftp"); session.setServerAliveInterval(92000); channel.connect(); ChannelSftp sftpChannel = (ChannelSftp) channel; sftpChannel.get(TEMP_PATH + SLASH + artifact.getFileName(), destDir); sftpChannel.exit(); session.disconnect(); File downloadedFile = new File(destDir, artifact.getFileName()); assertThat(downloadedFile).exists().hasSize(WAR_FILE_LENGTH); }
  • 64. Just say it public void shouldPreDeployApplication() { Artifact artifact = mock(Artifact.class); when(artifact.getFileName()) .thenReturn(ARTIFACT_FILE_NAME); ServerConfiguration config = new ServerConfiguration(ADDRESS, USER, KEY_FILE, TOMCAT_PATH, TEMP_PATH); Tomcat tomcat = new Tomcat(HTTP_TOMCAT_URL, config); tomcat.preDeploy(artifact, new FakeWar(WAR_FILE_LENGTH)); SSHServerAssert.assertThat(ARTIFACT_FILE_NAME) .existsOnServer(config).hasSize(WAR_FILE_LENGTH); }
  • 65. What is asserted? @Test public void testCompile_32Bit_FakeSourceFile() { CompilerSupport _32BitCompilerSupport = CompilerSupportFactory.getDefault32BitCompilerSupport(); testCompile_FakeSourceFile(_32BitCompilerSupport); }
  • 66. What is asserted? @Test public void testCompile_32Bit_FakeSourceFile() { CompilerSupport _32BitCompilerSupport = CompilerSupportFactory.getDefault32BitCompilerSupport(); testCompile_FakeSourceFile(_32BitCompilerSupport); } private void testCompile_FakeSourceFile( CompilerSupport compilerSupport) { compiledFiles = compilerSupport.compile(new File[] { new File("fake") }); assertThat(compiledFiles, is(emptyArray())); }
  • 67. Asserting everything public void invalidTxShouldBeCanceled() { String fileContent = FileUtils.getContentOfFile("response.csv"); assertTrue(fileContent.contains( "CANCEL,123,123cancel,billing_id_123_cancel,SUCCESS,")); }
  • 68. Asserting everything public void invalidTxShouldBeCanceled() { String fileContent = FileUtils.getContentOfFile("response.csv"); assertTrue(fileContent.contains( "CANCEL,123,123cancel,billing_id_123_cancel,SUCCESS,")); } public void invalidTxShouldBeCanceled() { String fileContent = FileUtils.getContentOfFile("response.csv"); TxDTOAssert.assertThat(fileContent) .hasTransaction("123cancel").withResultCode(SUCCESS); }
  • 70. Expected exceptions @Test(expectedExceptions = SmsException.class) public void shouldThrowException() throws SmsException { try { String s = gutExtractor.extractGut(„invalid gut”); System.out.println(s); } catch (SmsException e) { e.printStackTrace(); throw e; } }
  • 71. Expected exceptions @Test(expectedExceptions = SmsException.class) public void shouldThrowException() throws SmsException { String s = gutExtractor.extractGut(„invalid gut”); }
  • 72. Expected exceptions (with catch-exception) @Test public void shouldThrowException() throws SmsException { when(gutExtractor.extractGut(„invalid gut”)); then(caughtException()) .isInstanceOf(SmsException.class) .hasMessage("Invalid gut") .hasNoCause(); } http://code.google.com/p/catch-exception/
  • 73. Running SUT's code concurrently @Test(threadPoolSize = 3, invocationCount = 10) public void testServer() { // this method will be run in parallel by 3 thread // 10 invocations (in total) }
  • 74. Dependent test methods @Test public void shouldConnectToDB() { // verifying that you can // estabilish a connection with DB } @Test(dependsOnMethods = „shouldConnectToDB”) public void should…() { // some operations on DB }
  • 75. Know your tools • Unit testing framework  Additional libraries  Use of temporary file rule  Hamcrest, FEST, Mockito,  Listeners catch-exception, …  Concurrency • Build tool  @Before/@After  Parallel execution  Parametrized tests  CI  Test dependencies • IDE  Templates  Shortcuts
  • 76. What do you really want to test?
  • 77. What do you really want to test? @Test public void shouldAddAUser() { User user = new User(); userService.save(user); assertEquals(dao.getNbOfUsers(), 1); }
  • 78. You wanted to see that the number increased @Test public void shouldAddAUser() { Int nb = dao.getNbOfUsers(); User user = new User(); userService.save(user); assertEquals(dao.getNbOfUsers(), nb + 1); }
  • 80. Doing it wrong public void myTest() { SomeObject obj = new SomeObject( a, b, c, productCode()); // testing of obj here } private String productCode(){ String[] codes = {"Code A", "Code B", "Code C", "Code D"}; int index = rand.nextInt(codes.length); return codes[index]; }
  • 81. The dream of stronger, random-powered tests public void myTest() { SomeObject obj = new SomeObject( randomName(), randomValue(), ....); // testing of obj here } Does it make your test stronger?
  • 82. The dream of stronger, random-powered tests public void myTest() { SomeObject obj = new SomeObject( randomName(), randomValue(), ....); // testing of obj here } Does it make your test stronger? ...or does it only bring confusion? Test failed Expected SomeObject(„a”, „b”, ....) but got Expected SomeObject(„*&O*$NdlF”, „#idSLNF”, ....)
  • 84. There is more to it • Integration / end-to-end tests which are not parametrized (so they all try to set up jetty on port 8080), • Tests which should be really unit, but use Spring context to create objects, • Tests with a lot of dependencies between them (a nightmare to maintain!), • Tests which run slow • Tests which try to cover the deficiencies of production code and end up being a total mess, • etc., etc.
  • 85. Test-last? No! • makes people not write tests at all • makes people do only happy-testing • tests reflect the implementation
  • 86. Always TDD? For six or eight hours spread over the next few weeks I struggled to get the first test written and running. Writing tests for Eclipse plug-ins is not trivial, so it’s not surprising I had some trouble. [...] In six or eight hours of solid programming time, I can still make significant progress. If I’d just written some stuff and verified it by hand, I would probably have the final answer to whether my idea is actually worth money by now. Instead, all I have is a complicated test that doesn’t work, a pile of frustration, eight fewer hours in my life, and the motivation to write another essay. Ken Beck, Just Ship, Baby
  • 87. Treat tests as the first class citizens • do it everyday or forget about it • make tests readable using matchers, • use the right tool for the job builders and good names • and learn to use it! • test behaviour not methods • do not live with broken windows • be pragmatic about the tests you write • respect KISS, SRP, DRY (?) • TDD always? • write good code, and you will also write • what is the best way to test it? good tests unit/integration/end-to-end ? • or rather write good tests and you • automate! will get good code for free • always concentrate on what is worth • code review your tests testing • do more than happy path testing • ask yourself questions like: 'is it really important that X should send • do not make the reader learn the API, message Y to Z?' make it obvious • use the front door – state testing before • bad names lead to bad tests interaction testing (mockc)
  • 88. …questions? …rants? …hate speeches? …any other forms of expressing your ego? P.S. If you have some „interesting” tests, I would be happy to see them. Send them to me, please!
  • 89. Thank you! Thank you for watching these slides! You can learn more about wirting high quality tests by reading my book – „Practical Unit Testing with TestNG and Mockito”. Regards, Tomek Kaczanowski http://practicalunittesting.com