53
How to keep normal blood pressure using TDD

"How keep normal blood pressure using TDD" By Roman Loparev

  • Upload
    ciklum

  • View
    29

  • Download
    0

Embed Size (px)

Citation preview

Page 1: "How keep normal blood pressure using TDD" By Roman Loparev

How to keep normal blood pressure using TDD

Page 2: "How keep normal blood pressure using TDD" By Roman Loparev

A little bit about me

● Java developer at PrivatBank

● more than 3 years of experience

● much less experience in TDD

● blog: kastordriver.one

● e-mail: [email protected]

Page 3: "How keep normal blood pressure using TDD" By Roman Loparev

Agenda

● what is TDD?

● basic principles of technique

● how to write tests correctly

● tools from the arsenal of Java developer

● some code and examples

Page 4: "How keep normal blood pressure using TDD" By Roman Loparev

Pyramid of fate tests

Unit tests

Integration tests

Manual tests

Page 5: "How keep normal blood pressure using TDD" By Roman Loparev

What is TDD?

● tests first

● it is not about testing

● it is about design

● and little about documentation

● but they do not replace architecture and

design

Page 6: "How keep normal blood pressure using TDD" By Roman Loparev

Pros

● better design, because you think before writing

● documentation that we can trust

● fast feedback (faster than QA and debug)

● refactoring is encouraged

● minimalistic code

Page 7: "How keep normal blood pressure using TDD" By Roman Loparev

Cons

● not suitable for GUI and database schema development

● discipline is required

● discipline is required for all team members

● erroneous test leads to the erroneous code (problem?)

Page 8: "How keep normal blood pressure using TDD" By Roman Loparev

Test firstTest last

Page 9: "How keep normal blood pressure using TDD" By Roman Loparev

Test last● we concentrate on the parts of the code instead of design

● by the time of writing tests we get tired

● tests are being wrote taking into account rakes and crutches

● “test last” requires a powerful self-organization (only superhero

is able to do that)

Page 10: "How keep normal blood pressure using TDD" By Roman Loparev

Test first

● write tests on the first wave of enthusiasm

● incentive for write code - pass the test

● look at issue from the user's perspective

● the code is tested and is minimal

Page 11: "How keep normal blood pressure using TDD" By Roman Loparev

Three laws of TDD

● You must not write code while tests

are red

● You must not be farther than one

step from green line

● You must not write code more than

necessary for passing tests

Page 12: "How keep normal blood pressure using TDD" By Roman Loparev

How does it look?

● think before writing test

● formalize business requirements in tests

● name of test has to clearly describe the

purpose of the test

● check that the test fails

Note: Tests clarity should be more important than avoiding code duplication

RED

GREENREFACTOR

Page 13: "How keep normal blood pressure using TDD" By Roman Loparev

How does it look?

● write enough code to compile and pass

the test. No more

● check that the test is passed

● check all other tests

RED

REFACTOR GREEN

Page 14: "How keep normal blood pressure using TDD" By Roman Loparev

How does it look?

● get rid of duplication

● think about design

● go to “red” step

GREENREFACTOR

RED

Page 15: "How keep normal blood pressure using TDD" By Roman Loparev

Provide correct tests names

You should not:

● name test same as tested method

● name tests like: testSomeMethod1, testSomeMethod2...

Page 16: "How keep normal blood pressure using TDD" By Roman Loparev

Provide correct tests names

Name of test should:

● describe feature or specification

● describe purpose of test

● describe what object does, but not what it is

● When [Action] Then [Verification]

Page 17: "How keep normal blood pressure using TDD" By Roman Loparev
Page 18: "How keep normal blood pressure using TDD" By Roman Loparev

@Testpublic void whenNumberIsNotMultipleOf3And5ThenReturnTheSameNumber() { FizzBuzzGame fizzBuzz = new FizzBuzzGame(); assertEquals(“1”, fizzBuzz.fizzBuzzNumber(1));}

Page 19: "How keep normal blood pressure using TDD" By Roman Loparev

public class FizzBuzzGame { public String fizzBuzzNumber(int number) { return String.valueOf(1); }}

Page 20: "How keep normal blood pressure using TDD" By Roman Loparev

@Testpublic void whenNumberIsNotMultipleOf3And5ThenReturnTheSameNumber() { FizzBuzzGame fizzBuzz = new FizzBuzzGame(); assertEquals(“1”, fizzBuzz.fizzBuzzNumber(1)); assertEquals(“2”, fizzBuzz.fizzBuzzNumber(2));}

Page 21: "How keep normal blood pressure using TDD" By Roman Loparev

public class FizzBuzzGame { public String fizzBuzzNumber(int number) { return String.valueOf(number); }}

Page 22: "How keep normal blood pressure using TDD" By Roman Loparev

private FizzBuzzGame fizzBuzzGame;

@Beforepublic void setUp() throws Exception { fizzBuzzGame = new FizzBuzzGame();}

@Testpublic void whenNumberIsNotMultipleOf3And5ThenReturnTheSameNumber() { assertEquals("1", fizzBuzzGame.fizzBuzzNumber(1)); assertEquals("2", fizzBuzzGame.fizzBuzzNumber(2));}

@Testpublic void whenNumberIsMultipleOf3ThenReturnFizz() { assertEquals("Fizz", fizzBuzzGame.fizzBuzzNumber(3)); assertEquals("Fizz", fizzBuzzGame.fizzBuzzNumber(9));}

Page 23: "How keep normal blood pressure using TDD" By Roman Loparev

public class FizzBuzzGame {

public String fizzBuzzNumber(int number) { if (number % 3 == 0) return "Fizz"; return String.valueOf(number); }}

Page 24: "How keep normal blood pressure using TDD" By Roman Loparev

private FizzBuzzGame fizzBuzzGame;

@Beforepublic void setUp() throws Exception { fizzBuzzGame = new FizzBuzzGame();}

@Testpublic void whenNumberIsNotMultipleOf3And5ThenReturnTheSameNumber() { assertEquals("1", fizzBuzzGame.fizzBuzzNumber(1)); assertEquals("2", fizzBuzzGame.fizzBuzzNumber(2));}

@Testpublic void whenNumberIsMultipleOf3ThenReturnFizz() { assertEquals("Fizz", fizzBuzzGame.fizzBuzzNumber(3)); assertEquals("Fizz", fizzBuzzGame.fizzBuzzNumber(9));}

@Testpublic void whenNumberIsMultipleOf5ThenReturnBuzz() { assertEquals("Buzz", fizzBuzzGame.fizzBuzzNumber(5)); assertEquals("Buzz", fizzBuzzGame.fizzBuzzNumber(10));}

Page 25: "How keep normal blood pressure using TDD" By Roman Loparev

public class FizzBuzzGame {

public String fizzBuzzNumber(int number) { if (number % 3 == 0) return "Fizz"; if (number % 5 == 0) return "Buzz"; return String.valueOf(number); }}

Page 26: "How keep normal blood pressure using TDD" By Roman Loparev

private FizzBuzzGame fizzBuzzGame;

@Beforepublic void setUp() throws Exception { fizzBuzzGame = new FizzBuzzGame();}

@Testpublic void whenNumberIsNotMultipleOf3And5ThenReturnTheSameNumber() { assertEquals("1", fizzBuzzGame.fizzBuzzNumber(1)); assertEquals("2", fizzBuzzGame.fizzBuzzNumber(2));}

@Testpublic void whenNumberIsMultipleOf3ThenReturnFizz() { assertEquals("Fizz", fizzBuzzGame.fizzBuzzNumber(3)); assertEquals("Fizz", fizzBuzzGame.fizzBuzzNumber(9));}

@Testpublic void whenNumberIsMultipleOf5ThenReturnBazz() { assertEquals("Bazz", fizzBuzzGame.fizzBuzzNumber(5)); assertEquals("Bazz", fizzBuzzGame.fizzBuzzNumber(10));}

@Testpublic void whenNumberIsMultipleOf3And5ThenReturnFizzBazz() { assertEquals("FizzBazz", fizzBuzzGame.fizzBuzzNumber(15)); assertEquals("FizzBazz", fizzBuzzGame.fizzBuzzNumber(30));}

Page 27: "How keep normal blood pressure using TDD" By Roman Loparev

public class FizzBuzzGame {

public String fizzBuzzNumber(int number) { if (number % 3 == 0) return "Fizz"; if (number % 5 == 0) return "Bazz"; if (number % 3 == 0 && number % 5 == 0) return "FizzBazz"; return String.valueOf(number); }}

Page 28: "How keep normal blood pressure using TDD" By Roman Loparev

public class FizzBuzzGame {

public String fizzBuzzNumber(int number) { if (number % 3 == 0) return "Fizz"; if (number % 5 == 0) return "Bazz"; if (number % 3 == 0 && number % 5 == 0) return "FizzBazz"; return String.valueOf(number); }}

org.junit.ComparisonFailure: Expected :FizzBazzActual :Fizz. . .FizzBuzzTest.whenNumberIsMultipleOf3And5ThenReturnFizzBazz(FizzBuzzTest.java:36)

Page 29: "How keep normal blood pressure using TDD" By Roman Loparev

public class FizzBuzzGame {

public String fizzBuzzNumber(int number) { if (number % 3 == 0 && number % 5 == 0) return "FizzBazz"; if (number % 3 == 0) return "Fizz"; if (number % 5 == 0) return "Bazz"; return String.valueOf(number); }}

Page 30: "How keep normal blood pressure using TDD" By Roman Loparev

private FizzBuzzGame fizzBuzzGame;

@Beforepublic void setUp() throws Exception { fizzBuzzGame = new FizzBuzzGame();}

@Testpublic void whenNumberIsNotMultipleOf3And5ThenReturnTheSameNumber() { assertEquals("1", fizzBuzzGame.fizzBuzzNumber(1)); assertEquals("2", fizzBuzzGame.fizzBuzzNumber(2));}

@Testpublic void whenNumberIsMultipleOnlyOf3ThenReturnFizz() { assertEquals("Fizz", fizzBuzzGame.fizzBuzzNumber(3)); assertEquals("Fizz", fizzBuzzGame.fizzBuzzNumber(9));}

@Testpublic void whenNumberIsMultipleOnlyOf5ThenReturnBazz() { assertEquals("Bazz", fizzBuzzGame.fizzBuzzNumber(5)); assertEquals("Bazz", fizzBuzzGame.fizzBuzzNumber(10));}

@Testpublic void whenNumberIsMultipleOf3And5ThenReturnFizzBazz() { assertEquals("FizzBazz", fizzBuzzGame.fizzBuzzNumber(15)); assertEquals("FizzBazz", fizzBuzzGame.fizzBuzzNumber(30));}

Page 31: "How keep normal blood pressure using TDD" By Roman Loparev

public class FizzBuzzGame {

public String fizzBuzzNumber(int number) { StringBuilder result = new StringBuilder();

if (number % 3 == 0) { result.append("Fizz"); }

if (number % 5 == 0) { result.append("Bazz"); }

return result.length() == 0 ? String.valueOf(number): result.toString();

}}

Page 32: "How keep normal blood pressure using TDD" By Roman Loparev

Separate and rule your tests

http://www.kastordriver.one/2017/02/separate-and-rule-your-tests.html

Page 33: "How keep normal blood pressure using TDD" By Roman Loparev

Unit tests<plugin>

<groupId>org.apache.maven.plugins</groupId>

<artifactId>maven-surefire-plugin</artifactId>

<version>2.19</version>

<configuration>

<includes>

<include>**/*Test.java</include>

</includes>

</configuration>

</plugin>

Page 34: "How keep normal blood pressure using TDD" By Roman Loparev

Integration tests<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-failsafe-plugin</artifactId> <version>2.19.1</version> <configuration> <includes> <include>**/*IT.java</include> </includes> </configuration> <executions> <execution> <goals> <goal>integration-test</goal> <goal>verify</goal> </goals> </execution> </executions></plugin>

Page 35: "How keep normal blood pressure using TDD" By Roman Loparev

We don't have time to write unit tests

Should I write code in a single

class with hundreds methods

without other classes, design

patterns and so on? No? But I

do not have time for that!

http://www.yegor256.com/2015/07/16/fools-dont-write-unit-tests.html

Page 36: "How keep normal blood pressure using TDD" By Roman Loparev

Are You Still Debugging?

Unit testing is a technique that

completely replaces

debugging. If debugging is

required, the design is not

good enough.

http://www.yegor256.com/2016/02/09/are-you-still-debugging.html

Page 37: "How keep normal blood pressure using TDD" By Roman Loparev

Legacy code

Page 38: "How keep normal blood pressure using TDD" By Roman Loparev

Legacy code

● write tests for legacy code

● rename, extract method, extract

interface

● write tests again

● sorry, but no fun

Page 39: "How keep normal blood pressure using TDD" By Roman Loparev

● Mockito makes mocking very easy

● It is extremely easy to read mock code

● Mockito works in any environment and has no

external dependencies

Sip of mockito

Page 40: "How keep normal blood pressure using TDD" By Roman Loparev

import static org.mockito.Mockito.*;// mock creationList mockedList = mock(List.class);

// using mock object - it does not throw any "unexpected interaction" exceptionmockedList.add("one");mockedList.add("one");mockedList.clear();

// selective, explicit, highly readable verificationverify(mockedList, times(2)).add("one");verify(mockedList).clear();

You can verify interactions

Page 41: "How keep normal blood pressure using TDD" By Roman Loparev

@Test(expected = RuntimeException.class)public void test() throws Exception {

// you can mock concrete classes, not only interfaces LinkedList mockedList = mock(LinkedList.class);

// stubbing appears before the actual execution when(mockedList.get(0)).thenReturn("first"); when(mockedList.get(1)).thenThrow(new RuntimeException());

// the following prints "null" because get(999) was not stubbed assertNull(mockedList.get(999)); assertEquals("first", mockedList.get(0));

//throw RuntimeException mockedList.get(1);}

You can stub method calls

Page 42: "How keep normal blood pressure using TDD" By Roman Loparev

Be careful with mocks

● Don't mock type you don't own!

● Don't mock everything, it's an anti-pattern

● Don't mock value objects

Page 43: "How keep normal blood pressure using TDD" By Roman Loparev

Mockito discourages

● Can I mock static methods?○ No. Mockito prefers object orientation

and dependency injection over static, procedural code that is hard to understand and change.

● Can I mock private methods?○ No. From the standpoint of testing...

private methods don't exist.

Page 44: "How keep normal blood pressure using TDD" By Roman Loparev

● Supports Mockito-style mocking.

● Mocks constructors, static, private and final

methods.

Powermock

Page 45: "How keep normal blood pressure using TDD" By Roman Loparev

class FileUtils {

public static Set<String> readUniqueWords(String path) throws IOException {

String text = new String(Files.readAllBytes(Paths.get(path)), "UTF-8");

Set<String> words = new HashSet<>();

for (String word : text.split(" ")) { words.add(word); }

return words; }}

Page 46: "How keep normal blood pressure using TDD" By Roman Loparev

@RunWith(PowerMockRunner.class)@PrepareForTest({Files.class, FileUtils.class})public class FileUtilsTest {

@Test public void readUniqueWordsMustReturnOnlyUniqueWords() throws Exception { final String somePath = "somePath"; Path fakePath = Paths.get(somePath);

PowerMockito.mockStatic(Files.class); when(Files.readAllBytes(fakePath)).thenReturn("One two two three".getBytes());

Set<String> result = FileUtils.readUniqueWords(somePath); assertEquals(3, result.size()); assertTrue(result.contains("One")); assertTrue(result.contains("two")); assertTrue(result.contains("three")); }}

Page 47: "How keep normal blood pressure using TDD" By Roman Loparev

class Text {

private final String path;

Text(String src) { this.path = src; }

public String readText() throws IOException { return new String(Files.readAllBytes(Paths.get(this.path)), "UTF-8"); }}

Page 48: "How keep normal blood pressure using TDD" By Roman Loparev

public class UniqueWords {

private final String text;

UniqueWords(String txt) { this.text = txt; }

public Set<String> readUniqueWords() { Set<String> words = new HashSet<>();

for (String word : this.text.split(" ")) { words.add(word); }

return words; }}

Page 49: "How keep normal blood pressure using TDD" By Roman Loparev

public class UniqueWordsTest {

@Test public void readUniqueWordsMustReturnOnlyUniqueWords() throws Exception { Set<String> result = new UniqueWords("One two two three")

.readUniqueWords();

assertEquals(3, result.size()); assertTrue(result.contains("One")); assertTrue(result.contains("two")); assertTrue(result.contains("three")); }}

Page 50: "How keep normal blood pressure using TDD" By Roman Loparev

Odd man out

Page 51: "How keep normal blood pressure using TDD" By Roman Loparev

Cobertura maven plugin allows you:

● Check the coverage percentages for unit tests and integration tests

● fail the build if the targets are not met

Keep a code coverage on a radar

http://www.kastordriver.one/2017/02/keep-code-coverage-on-radar.html

Page 53: "How keep normal blood pressure using TDD" By Roman Loparev

Thank you for your attention