2. 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: KastorDriver@gmail.com
3. Agenda
● what is TDD?
● basic principles of technique
● how to write tests correctly
● tools from the arsenal of Java developer
● some code and examples
4. Pyramid of fate tests
Unit tests
Integration tests
Manual
tests
5. 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
6. 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
7. 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?)
9. 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)
10. 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
11. 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
12. 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
13. 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
14. How does it look?
● get rid of duplication
● think about design
● go to “red” step
GREENREFACTOR
RED
15. Provide correct tests names
You should not:
● name test same as tested method
● name tests like: testSomeMethod1, testSomeMethod2...
16. 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]
35. 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
36. 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
38. Legacy code
● write tests for legacy code
● rename, extract method, extract
interface
● write tests again
● sorry, but no fun
39. ● 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
40. import static org.mockito.Mockito.*;
// mock creation
List mockedList = mock(List.class);
// using mock object - it does not throw any "unexpected interaction" exception
mockedList.add("one");
mockedList.add("one");
mockedList.clear();
// selective, explicit, highly readable verification
verify(mockedList, times(2)).add("one");
verify(mockedList).clear();
You can verify interactions
41. @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
42. 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
43. 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.
44. ● Supports Mockito-style mocking.
● Mocks constructors, static, private and final
methods.
Powermock
45. 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;
}
}
46. @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"));
}
}
47. 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");
}
}
48. 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;
}
}
49. 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"));
}
}
51. 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
52. Useful links
Kent Beck "Test Driven Development"
Андрей Солнцев “Пацан накодил - пацан протестил!
Mockito wiki
Николай Алименков "Сага о том, как Java-
разработчики должны тестировать свои
приложения"
Victor Farcic, Alex Garcia "Test-Driven Java Development"