object-oriented flavor for junit tests

31
/24 @yegor256 1 Yegor Bugayenko Object-Oriented Flavor for JUnit Tests

Upload: yegor-bugayenko

Post on 22-Jan-2018

358 views

Category:

Technology


2 download

TRANSCRIPT

/24@yegor256 1

Yegor Bugayenko

Object-Oriented Flavor for JUnit Tests

/24@yegor256 2

F.I.R.S.T.:Fast Isolated/Independent Repeatable Self-validating Thorough and Timely

— Robert MartinClean Code

/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.

/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

/24@yegor256 5

I believe that one anti-patternis still missing:

The algorithmProvided we’re talking about OOP

/24@yegor256 6

xUnit test method isbasically a procedure.

/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.Output3.Assertion

/24@yegor256 8

A test method must have nothing but a single statement:

assertThat()Provided we’re talking about Java

/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”)) ); } }

/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%”)) );

/24@yegor256 11

Hamcrest

By the way, this is the anagram for “matchers”.

/24@yegor256 12Some 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

/24@yegor256 13

Obvious benefits:Reduced complexity Immutable objects Shared “matchers” Fake objects and no mocking Better design (more object-oriented)

/24@yegor256

Reduced Complexity14

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

/24@yegor256

Immutable Objects15

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

/24@yegor256

Shared Matchers16

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

/24@yegor256

No Mocking17

void testWorksAsExpected() { assertThat( new Book(“Дон Кихот”, “UTF-8”, Locale.RUSSIAN), new HasURL(new StringContains(“%D0%94%D0%BE%D0”)) ); }

No assumptions No false positives

/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

/24@yegor256 19

OpenJDK

RandomStreamTest.java

java.util.Randomfor

/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); }

/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() ); }

/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() ); }

/24@yegor256 23

cactoos

www.cactoos.org

/24@yegor256 24

new Pipe( new TextAsInput(“Hello, world!”), new FileAsOutput(new File(“test.txt”)) ).push();

/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”) ); }

/24@yegor256 26

Input input = new TeeInput( new TextAsInput(“Hello, world!”), new FileAsOutput(new File(“test.txt”)) );

input.read();

new LengthOfInput(input).asValue();

6168af9

/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”) ) ); }

/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”) ) ); }

/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@yegor256 30The article on the blog:

/30@yegor256 31

[email protected]