Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Object-Oriented Flavor for JUnit Tests

433 views

Published on

JEEConf 2017; 27 May 2017; Kiev, Ukraine; video is here: https://www.youtube.com/watch?v=CCr8hRE_TUs

Published in: Technology
  • Be the first to comment

  • Be the first to like this

Object-Oriented Flavor for JUnit Tests

  1. 1. /24@yegor256 1 Yegor Bugayenko Object-Oriented Flavor for JUnit Tests
  2. 2. /24@yegor256 2 F.I.R.S.T.: Fast Isolated/Independent Repeatable Self-validating Thorough and Timely — Robert Martin
 Clean Code
  3. 3. /24@yegor256 3 There are books: Kent Beck, Test-Driven Development by Example, 2000. Johannes Link, Unit testing in Java, 2003. Ted Husted and Vincent Massol, JUnit in Action, 2003. Andy Hunt and David Thomas, Pragmatic Unit Testing in C# with NUnit, 2003. Gerard Meszaros, XUnit Test Patterns: Refactoring Test Code, 2007. Nat Pryce and Steve Freeman, Growing Object-Oriented Software: Guided by Tests, 2009. Lasse Koskela, Effective Unit Testing: A Guide for Java Developers, 2013. J. B. Rainsberger, JUnit recipes, 2014. Sujoy Acharya, Mastering Unit Testing Using Mockito and JUnit, 2014.
  4. 4. /24@yegor256 4 Unit testing anti-patterns: Happy Path Tests Validation and Boundary Easy Tests The Giant The Cuckoo The Conjoined Twins The Slow Poke Anal Probe Test It All Line Hitter Wait and See The Silent Catcher Chain Gang The Mockery The Free Ride The Local Hero Wet Floor The Flickering Test The Environmental Vandal Second Class Citizens The Secret Catcher Logic in Tests Code Matching Misleading Tests Not Asserting Asserting on Not-Null
  5. 5. /24@yegor256 5 I believe that one anti-pattern
 is still missing: The algorithm Provided we’re talking about OOP
  6. 6. /24@yegor256 6 xUnit test method is
 basically a procedure.
  7. 7. /24@yegor256 7 class BookTest { @Test void testWorksAsExpected() { Book book = new Book(); book.setLanguage(Locale.RUSSIAN); book.setEncoding(“UTF-8”); book.setTitle(“Дон Кихот”); assertTrue(book.getURL().contains(“%D0%94%D0%BE%D0”)); } } 1.Algorithm 2.Output 3.Assertion
  8. 8. /24@yegor256 8 A test method must have nothing but a single statement: assertThat() Provided we’re talking about Java
  9. 9. /24@yegor256 9 class BookTest { @Test void testWorksAsExpected() { // nothing goes here assertThat( new Book(“Дон Кихот”, “UTF-8”, Locale.RUSSIAN), new HasURL(new StringContains(“%D0%94%D0%BE%D0”)) ); } }
  10. 10. /24@yegor256 10 Assert that the book is similar to a book that has a URL that contains a string that is equal to “%D0%94”. assertThat( new Book(“Дон Кихот”, “UTF-8”, Locale.RUSSIAN), new HasURL(new StringContains(“%D0%94%”)) );
  11. 11. /24@yegor256 11 Hamcrest By the way, this is the anagram for “matchers”.
  12. 12. /24@yegor256 12 Some of anti-patterns will just disappear: Happy Path Tests Validation and Boundary Easy Tests The Giant The Cuckoo The Conjoined Twins The Slow Poke Anal Probe Test It All Line Hitter Wait and See The Silent Catcher Chain Gang The Mockery The Free Ride The Local Hero Wet Floor The Flickering Test The Environmental Vandal Second Class Citizens The Secret Catcher Logic in Tests Code Matching Misleading Tests Not Asserting Asserting on Not-Null
  13. 13. /24@yegor256 13 Obvious benefits: Reduced complexity Immutable objects Shared “matchers” Fake objects and no mocking Better design (more object-oriented)
  14. 14. /24@yegor256 Reduced Complexity 14 void testWorksAsExpected() { assertThat( new Book(“Дон Кихот”, “UTF-8”, Locale.RUSSIAN), new HasURL(new StringContains(“%D0%94%D0%BE%D0”)) ); } No free ride No multi asserts No @Before/@After
  15. 15. /24@yegor256 Immutable Objects 15 void testWorksAsExpected() { assertThat( new Book(“Дон Кихот”, “UTF-8”, Locale.RUSSIAN), new HasURL(new StringContains(“%D0%94%D0%BE%D0”)) ); } No setters No temporal coupling No procedures
  16. 16. /24@yegor256 Shared Matchers 16 void testWorksAsExpected() { assertThat( new Book(“Дон Кихот”, “UTF-8”, Locale.RUSSIAN), new HasURL(new StringContains(“%D0%94%D0%BE%D0”)) ); } No private static methods No duplication Cleaner logs
  17. 17. /24@yegor256 No Mocking 17 void testWorksAsExpected() { assertThat( new Book(“Дон Кихот”, “UTF-8”, Locale.RUSSIAN), new HasURL(new StringContains(“%D0%94%D0%BE%D0”)) ); } No assumptions No false positives
  18. 18. /24@yegor256 18 class BookTest { @Test void testWorksAsExpected() { Book b = new Book(“Дон Кихот”, “UTF-8”, Locale.RUSSIAN); Matcher m = new HasURL(new StringContains(“%D0%94%D0%BE%D0”)); assertThat(b, m); } } 1.Object 2.Matcher 3.Assertion
  19. 19. /24@yegor256 19 OpenJDK RandomStreamTest.java java.util.Random for
  20. 20. /24@yegor256 20 @Test public void testIntStream() { final long seed = System.currentTimeMillis(); final Random r1 = new Random(seed); final int[] a = new int[SIZE]; for (int i=0; i < SIZE; i++) { a[i] = r1.nextInt(); } final Random r2 = new Random(seed); final int[] b = r2.ints().limit(SIZE).toArray(); assertEquals(a, b); }
  21. 21. /24@yegor256 21 private static class ArrayFromRandom { private final Random random; ArrayFromRandom(Random r) { this.random = r; } int[] toArray(int s) { final int[] a = new int[s]; for (int i=0; i < s; i++) { a[i] = this.random.nextInt(); } return a; } } @Test public void testIntStream() { final long seed = System.currentTimeMillis(); assertEquals( new ArrayFromRandom( new Random(seed) ).toArray(SIZE), new Random(seed).ints().limit(SIZE).toArray() ); }
  22. 22. /24@yegor256 22 @Test public void testIntStream() { assertEquals( new ArrayFromRandom( new Random(System.currentTimeMillis() as seed) ).toArray(SIZE), new Random(seed).ints().limit(SIZE).toArray() ); }
  23. 23. /24@yegor256 23 cactoos www.cactoos.org
  24. 24. /24@yegor256 24 new Pipe( new TextAsInput(“Hello, world!”), new FileAsOutput(new File(“test.txt”)) ).push();
  25. 25. /24@yegor256 25 @Test public void canCopyTextToByteArray() { ByteArrayOutputStream baos = new ByteArrayOutputStream(); new Pipe( new TextAsInput(“Hello, world!”), new OutputStreamAsOutput(baos) ).push(); assertThat( new String(baos.toByteArray()), Matchers.containsString(“Hello”) ); }
  26. 26. /24@yegor256 26 Input input = new TeeInput( new TextAsInput(“Hello, world!”), new FileAsOutput(new File(“test.txt”)) ); input.read(); new LengthOfInput(input).asValue(); 6168af9
  27. 27. /24@yegor256 27 @Test public void canCopyTextToByteArray() { ByteArrayOutputStream baos = new ByteArrayOutputStream(); assertThat( new InputAsText( new TeeInput( new TextAsInput(“Hello, world!”), new OutputStreamAsOutput(baos) ) ), Matchers.allOf( equalTo(new String(baos.toByteArray())), containsString(“Hello”) ) ); }
  28. 28. /24@yegor256 28 @Test public void canCopyTextToByteArray() { ByteArrayOutputStream baos; assertThat( new InputAsText( new TeeInput( new TextAsInput(“Hello, world!”), new OutputStreamAsOutput(baos = new ByteArrayOutputStream()) ) ), Matchers.allOf( equalTo(new String(baos.toByteArray())), containsString(“Hello”) ) ); }
  29. 29. /24@yegor256 29 @Test public void canCopyTextToByteArray() { assertThat( new InputAsText( new TeeInput( new TextAsInput(“Hello, world!”), new OutputStreamAsOutput( new ByteArrayOutputStream() as baos ) ) ), Matchers.allOf( equalTo(new String(baos.toByteArray())), containsString(“Hello”) ) ); }
  30. 30. /30@yegor256 30 The article on the blog:
  31. 31. /30@yegor256 31 shop@yegor256.com

×