1 / 93

Test Driven Development Testing Cooking Book

Test Driven Development Testing Cooking Book. Jonathan Lalou Software Architect Agile Development Scrum Master January 24th, 2012. Disclaimer on this training session. Expected attendees level: beginner / middle Java as well as C++, DotNet, etc. No difficulty on Java Slow rise Targets:

Download Presentation

Test Driven Development Testing Cooking Book

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Test Driven DevelopmentTesting Cooking Book Jonathan Lalou Software Architect Agile Development Scrum Master January 24th, 2012

  2. Disclaimer on this training session • Expected attendees level: beginner / middle • Java as well as C++, DotNet, etc. • No difficulty on Java • Slow rise • Targets: • Search, think, try, investigate… no solution “out of the box” • Transmit best practices • Give return of experiences • Improve your skills • Needed: • Brain, pencil, paper • IDE (Eclipse, IDEA) • Jars: JUnit, EasyMock, Log4j • Planned duration: 2h

  3. Test Driven Development Concepts Interest Among other Agile methods Unit Test Cooking Book Basics Methods within methods Layers / Mocks Exceptions Private methods Other Tests Integration tests Runtime tests Stress tests Limitations and Vulnerabilities Plan

  4. MySelf! • Jonathan LALOU • Mines Nancy 2000-2003 • Cadextan / SunGard since 2005 • BNP Arbitrage since 2007: • PW • European PB

  5. BKN Agility • Business Knowledge Network • Agility • Scrum • General (2 sessions, once a month) • Scrum master • Product Owner • TDD (1 session, once a month) • Continuous Integration • Lean • Etc. • For Sungard consultants • For Sungard customers

  6. Who we are Test Driven Development

  7. Concepts • Write test before implementation • Lifecycle • Write a test • Check it fails • Write minimum code to make the test succeed • Check it succeeds • Refactor

  8. Interest • Improve specifications • Provide validation for development • Less debug • Less regression • Safe refactoring • Automatization

  9. Among Other Agile Methods • Other famous Agile methods: Scrum, XP, Continuous Integration • XP loves TDD • One codes the test • One codes the needed program • Continuous Integration • Runs complete test set • Raises errors soon • Version Control System  easy roll back

  10. Experience… • Covertures: 80% • Need update • To be run before each commit • Strategy • Quick and dirty: • With private methods • At the bottom of the very class • Need compilation • “No private” methods • In the same package, in another folder

  11. Who we are Unit Test Cooking Book

  12. Who we are Basics for Beginners

  13. Basic (1) Example: “write a service that sums two integers”

  14. Basic (2) Mode “I’ve just got out of school”: 1 publicclass Summer { 2 public Integer sum(Integer a, Integer b){ 3 return a+b; 4 } 5 6 publicstaticvoid main(String[] args){ 7 int foo = new Summer().sum(12, 5); 8 if (foo != 17){ 9 System.err.println("There is an error"); 10 }else{ 11 System.out.println("this is OK"); 12 } 13 14 } 15 }

  15. Basic (3) Mode “TDD” 1/ Create empty class Summer: 1 publicclass Summer { 2 public Integer sum(Integer a, Integer b){ 3 return null; 4 } 2/ Create unit test: 1 publicclass SummerUnitTest extends TestCase { 2 publicvoid testSum() throws Exception { 3 assertEquals(17, new Summer().sum(15, 2)); 4 } 5 } 3/ Complete class Summer: 1 publicclass Summer { 2 public Integer sum(Integer a, Integer b){ 3 return a+b; 4 }

  16. Basic (4) • Framework JUnit • Open source, quasi standard • Integration within IntelliJ IDEA, Eclipse, Netbeans, etc. • Integration with Maven (plugin Surefire) • Galaxy of “XUnit”: NUnit, PHPUnit, PyUnit, etc. • Other framework: TestNG, etc. • JUnit 3 • setUp() • tearDown() • void test*() • JUnit 4 • @Before • @After • @Test

  17. Basic (5): Expectations • Expectations: • Success • Failure • Error • Asserts: • assertEquals • assertSame • assertTrue / assertFalse • assertNull / assertNotNull • fail

  18. Exercise 1 Write a class with following services • get the maximum of two integers • get the maximum of an array of integers • flip an array of integers • says whether a String is a valid email address (please do not use Apache Commons, Spring, etc. in unit tests exercises)

  19. Exercise 1: correction publicclass Exercise1 { public Integer maxOfTwo(Integer a, Integer b) { return a > b ? a : b; } public Integer maxOfArray(int[] args) { /*if (args == null || args.length == 0) { return null; }*/ Integer max = Integer.MIN_VALUE; for (int i = 0; i < args.length; i++) { max = maxOfTwo(max, args[i]); } return max; } publicint[] flip(int[] source) { finalint[] answer = newint[source.length]; for (int i = 0; i < source.length; i++) { answer[i] = source[source.length - i - 1]; } return answer; } }

  20. Exercise 1: correction (JUnit 3) publicclassExercise1UnitTestJUnit3extendsTestCase{ privateExercise1exercise1; protectedvoid setUp() { exercise1 = newExercise1(); } protectedvoid tearDown() { exercise1 = null; } publicvoid testMaxOfTwo() throws Exception { Assert.assertEquals(5, exercise1.maxOfTwo(4, 5).intValue()); } publicvoid testMaxOfArray() { Assert.assertEquals(15, exercise1.maxOfArray(newint[]{5, 6, 3, 15, 4, 9, 14}).intValue()); } publicvoid testFlip() { finalint[] source = newint[]{1, 2, 5, 4, 6}; finalint[] expectedAnswer = newint[]{6, 4, 5, 2, 1}; finalint[] actualAnswer = exercise1.flip(source); Assert.assertNotNull(actualAnswer); Assert.assertEquals(actualAnswer.length, source.length); for (int i = 0; i < actualAnswer.length; i++) { Assert.assertEquals(expectedAnswer[i], actualAnswer[i]); } } }

  21. Exercise 1: correction (JUnit 4) publicclass Exercise1UnitTest { private Exercise1 exercise1; @org.junit.Before publicvoid methodBefore() { exercise1 = new Exercise1(); } @org.junit.After publicvoid methodAfter() { exercise1 = null; } @Test publicvoid maxOfTwo() throws Exception { Assert.assertEquals(5, exercise1.maxOfTwo(4, 5).intValue()); } @Test publicvoid maxOfArray() { Assert.assertEquals(15, exercise1.maxOfArray(newint[]{5, 6, 3, 15, 4, 9, 14}).intValue()); } @Test publicvoid flip() { finalint[] source = newint[]{1, 2, 5, 4, 6}; finalint[] expectedAnswer = newint[]{6, 4, 5, 2, 1}; finalint[] actualAnswer = exercise1.flip(source); Assert.assertNotNull(actualAnswer); Assert.assertEquals(actualAnswer.length, source.length); for (int i = 0; i < actualAnswer.length; i++) { Assert.assertEquals(expectedAnswer[i], actualAnswer[i]); } } }

  22. Best Practices (1) • For each class X, create a class XUnitTest extends TestCase • X in src/ folder, XUnitTest in test/unit • Use any value, rather than basic values (0, 1) • 546541 • 95.1215 • “myVariableName” • Beware of: • Arrays and Collections  asserts on elements

  23. Exercise 2 Write following services: • Get the absolute value of a Double • Get f: x x² • Get g: (x,y) y(xy) • Reminder: • x < 0  |x| = -x • x >= 0  |x| = +x

  24. Exercise 2: Correction (1) package lalou.jonathan.tdd; /** * User: JonathanLalou * Date: 9/22/11 * Time: 1:53 PM * $Id$ */ publicclass Exercise2 { public Double absoluteValue(Double x) { if (x > 0) return x; elsereturn -x; } public Double f(Double x){ return Math.sqrt(Math.pow(x, 2)); } public Double g (Double x, Double y){ return Math.pow(Math.pow(x, y), 1/y); } }

  25. Exercise 2: Correction (2) publicclass Exercise2UnitTest { private Exercise2 exercise2; @Before publicvoid setUp(){ exercise2 = new Exercise2(); } @Test publicvoid testAbsoluteValue_positive() throws Exception { Assert.assertEquals(3.2, exercise2.absoluteValue(3.2)); } // the second test IS needed @Test publicvoid testAbsoluteValue_negative() throws Exception { Assert.assertEquals(4.5, exercise2.absoluteValue(-4.5)); } @Test publicvoid testF() throws Exception { finaldouble expected = 6.9999; Assert.assertEquals(expected, exercise2.f(expected)); } // … }

  26. Exercise 2: Correction (3) @Test publicvoid testG() throws Exception { finaldouble expected = 6.9999999; final Double power = 99.99987654; Assert.assertEquals(expected, exercise2.g(expected, power)); } …  junit.framework.AssertionFailedError: expected:<6.9999999> but was:<6.999999899999999> at lalou.jonathan.tdd.Exercise2UnitTest.testG(Exercise2UnitTest.java:41) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) (…) at org.junit.runner.JUnitCore.run(JUnitCore.java:157) (…) at com.intellij.rt.execution.application.AppMain.main(AppMain.java:120) Process finished with exit code -1

  27. Exercise 2: Correction (4) @Test publicvoid testG() throws Exception { finaldouble expected = 6.9999999; final Double power = 99.99987654; final Double epsilon = 0.1; Assert.assertEquals( expected, exercise2.g(expected, power), epsilon); }

  28. Best Practices (2) • Test every possible switch • Beware of: • Double, Float, etc.  add an epsilon

  29. Exercise 3 • A complex number: (x, y) / (ρ,θ) • Write the method that gives the square of the module • Write unit test

  30. Exercise 3: Correction (1) 1 publicclass Complex { 2 privatefinal Double x, y, rho, theta; 3 4 public Complex(Double x, Double y, Double rho, Double theta) { 5 this.rho = rho; 6 this.theta = theta; 7 this.x = x; 8 this.y = y; 9 } 10 11 public Double getSquaredModule(){ 12 returnx*x + y*y; 13 } 14 }

  31. Exercise 3: Correction (2) 1 publicvoid testGetSquaredModule_firstAttempt() { 2 final Double expected = 5.0, epsilon = 0.01; 3 final Complex complex = new Complex(1.0, 2.0, Math.sqrt(5), 1.10714872); 4 final Double actual = complex.getSquaredModule(); 5 assertEquals(expected, actual, epsilon); 6 } 7 8 publicvoid testGetSquaredModule_secondAttempt() { 9 final Double expected = 5.0, epsilon = 0.01; 10 final Complex complex = new Complex(0.0, 0.0, Math.sqrt(5), 1.10714872); 11 final Double actual = complex.getSquaredModule(); 12 assertNotSame(expected, actual); 13 }

  32. Exercise 3: Correction (3) 1 publicvoid testGetSquaredModule_right() { 2 final Double expected = 5.0, epsilon = 0.01; • final Complex complex = new Complex(1.0, 2.0, 0.0, 0.0); 4 final Double actual = complex.getSquaredModule(); 5 assertEquals(expected, actual, epsilon); 6 }

  33. Best Practices (3) • Setup the minimum of needed fields

  34. Methods within a method (1) • Errors can offset each other • Idea: • test only one method at a time • override / mock other methods • check other methods were called with rights parameters • Not “pure-TDD” (tests before code) • Many different ways to test the same code

  35. Methods within a method (2) 1 publicclass MethodWithinMethod { 2 3 public Integer sum(Integer... params) { 4 Integer answer = 0; 5 for (Integer param : params) { 6 answer += param; 7 } 8 return answer; 9 } 10 11 public Integer sumAndQuadruple(Integer... params) { 12 final Integer summed = sum(params); 13 return4 * summed; 14 } 15 }

  36. Methods within a method (3) 1 @Test 2 publicvoid testSum() throws Exception { 3 assertEquals(15, methodWithinMethod.sum(1, 2, 3, 4, 5).intValue()); 4 } 5 6 @Test 7 publicvoid testSumAndQuadruple_bad() throws Exception { 8 assertEquals(60, methodWithinMethod.sumAndQuadruple(1, 2, 3, 4, 5).intValue()); 9 }

  37. Methods within a method (4) 1 @Test 2 publicvoid testSumAndQuadruple_good() throws Exception { 3 final String OK = "OK"; 4 final Integer[] params = new Integer[]{1, 2, 3, 4, 5}; 5 final Integer summed = -1; 6 final StringBuffer sb = new StringBuffer(); 7 methodWithinMethod = new MethodWithinMethod(){ 8 public Integer sum(Integer... _params) { 9 assertEquals(_params, params); 10 sb.append(OK); 11 returnsummed; 12 } • }; • assertEquals(0, sb.toString().length()); • // before calling method • assertEquals("", sb.toString()); • assertEquals(-4, methodWithinMethod.sumAndQuadruple(params).intValue()); • assertEquals(OK, sb.toString()); • }

  38. Exercise 5: method within method • Write a class with two methods • First: to log input/outputs • Second: logs and inverses a non null Integer (and returns 0 for 0) • (excercice#5 is before #4 ;-) )

  39. Exercise 5 : correction (1) 1 publicclass Exercise5 { 2 publicvoid log(String message) { 3 System.out.println(message); 4 } 5 6 public Double inverse(Integer param) { 7 final Double answer; 8 log("called with parameter: " + param); 9 answer = param == 0 ? 0.0 : 1 / (double) param; 10 log("exit with result: " + answer); 11 return answer; 12 } 13 }

  40. Exercise 5 : correction (2) publicvoid testInverse() { final List<String> witness = new ArrayList<String>(2); final Exercise5 exercise5 = new Exercise5() { publicvoid log(String message) { assertTrue(message.equalsIgnoreCase("called with parameter: 4") || message.equalsIgnoreCase("exit with result: 0.25")); witness.remove(message); } }; final Integer param = 4; final Double expectedAnswer = 0.25; final Double actualAnswer; witness.add("called with parameter: 4"); witness.add("exit with result: 0.25"); // check before run assertFalse(witness.isEmpty()); actualAnswer = exercise5.inverse(param); assertNotNull(actualAnswer); assertEquals(expectedAnswer, actualAnswer, 0.000001); // check after run assertTrue(witness.isEmpty()); }

  41. Who we are Advanced

  42. Mocks

  43. Layers • Testing layers should deserve a complete training session! • Unit test: test only one class behavior: • Service • DAO • Logic • EJB • Presentation • Form • Action • Architecture in layers: • Unit test strategy: • Unit test each layer • Mock other layers • Integration tests

  44. Mocks • Use case / interest: • Non-deterministic results • Precalculate state • Fastness • Not yet implemented actual class • Mocks ~ AOP • Mocks  Time consuming! Caution

  45. Mocks / Stubs / Fakes • Mock • Stub • Provide minimal implementation • Fake • Emulate a service, eg: client/server

  46. Mocks: frameworks in Java • Mockit • Mockito • EasyMock • JMock • PowerMock • …

  47. Mocks: EasyMock (old): setup 1 private TreeNodeDetailVarDao treeNodeDetailVarDao; 3 private MockControl<TreeNodeDetailVarDao> treeNodeDetailVarDaoMockControl; 10 @Before() 11 publicvoid setUp() throws Exception { 12 treeNodeDetailVarDaoMockControl = MockControl.createStrictControl(TreeNodeDetailVarDao.class); 13 treeNodeDetailVarDao = treeNodeDetailVarDaoMockControl.getMock(); 14 }

  48. Mocks: EasyMock (old): test treeNodeDetailVarDao.getTreeNodeDetailVarByTreeNodeId(treeNodeId); treeNodeDetailVarDaoMockControl.setReturnValue(12345); treeNodeDetailVarDaoMockControl.replay(); genericDtoService.getVarDistributionTOByTreeNodeId(treeNodeId, numberOfBars); treeNodeDetailVarDaoMockControl.verify();

  49. Mocks: EasyMock (new) • “A la” Mockito 1 expect( 2 shiftListDao.findLastUpdateDateForShiftTypeAndValueDate(ShiftType.STRESS_VAR, valueDate)). 3 andReturn(updateDateInDB); 4 5 // shiftListDao.findLastUpdateDateForShiftTypeAndValueDate(ShiftType.STRESS_VAR, valueDate); 6 // shiftListDaoMockControl.setReturnValue(updateDateInDB);

  50. Exercice 4 • Three DAOs • PeopleDAO • PortfolioDAO • InstrumentPriceDAO • One service that gets the value of someone’s portfolio • One service that gets the total value all portfolios

More Related