/38@yegor256 1
Yegor Bugayenko
Object-Oriented JUnit Tests
/38@yegor256 2
Why OOP?
/38@yegor256 3
yegor256/hangman
11
@funivan
/38@yegor256 4
Volume 2
$20
Free shipment
/38@yegor256 5
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
Forty Foot Pole
Test With No Name
Excessive Setup
The Dead Tree
The Turing Test
The Mother Hen
The Sleeper
The Butterfly
Doppelgänger
The Inspector
Structured Inspection
The Cupcake
/38@yegor256
Dependencies
6
are evil
Unbreakable
/38@yegor256 7
class Book {
private int id;
String title() {
return Database.getInstance().fetch(
“SELECT title FROM book WHERE id=?”,

this.id
);
}
} String title = new Book().title();
/38@yegor256 8
Book
BookTest
DatabaseSomething
/38@yegor256 9
class Book {
private int id;
String title() {
return DbUtils.fetch(
“SELECT title FROM book WHERE id=?”,

this.id
);
}
}
static
Johan Haleby
/38@yegor256 10
class Book {
private int id;
String title() {
return Database.getInstance().fetch(
“SELECT title FROM book WHERE id=?”,

this.id
);
}
}
global
/38@yegor256 11
class DbUtils {
private static int port;
static String fetch(String sql) {
// ..
}
}
class Database {
private static Database INSTANCE;
private int port;
private Database() {}
static Database getInstance() {
if (Database.INSTANCE == null) {
Database.INSTANCE = new Database();
}
return Database.INSTANCE;
}
String fetch(String sql) {
// ..
}
}
/38@yegor256 12
class DbUtils {
private static int port;
static String fetch(String sql) {
// ..
}
}
class Database {
private static Database INSTANCE;
private int port;
private Database() {}
static Database getInstance() {
if (Database.INSTANCE == null) {
Database.INSTANCE = new Database();
}
return Database.INSTANCE;
}
static void setInstance(Database db) {
Database.INSTANCE = db;
}
String fetch(String sql) {
// ..
}
}
/38@yegor256 13
class Book {
private int id;
String title() {
return new Database().fetch(
“SELECT title FROM book WHERE id=?”,

this.id
);
}
}
new
/38@yegor256 14
class Book {
private int id;
private Database database;
Book() {
this(new Database());
}
Book(Database db) {
this.database = db;
}
String title() {
return this.database.fetch(
“SELECT title FROM book WHERE id=?”,

this.id
);
}
}
DependencyInjection
/38@yegor256 15
new Book(new NotRealDatabase());
class NotRealDatabase implements Database {
// ...
}
interfaces
@Override
/38@yegor256 16
static
evil!
singletons
new
interface-less
/38@yegor256
Mocking
17
is evil
Ad hoc
/38@yegor256 18
static import org.mockito.Mockito.*;
class BookTest {
@Test
public canFetchTitleFromDatabase() {
Database db = mock(Database.class);
doReturn(“UML Distilled”).when(db).fetch(
“SELECT title FROM book WHERE id=?”, 123
);
Book book = new Book(db, 123);
assert book.title().equals(“UML Distilled”);
}
}
/38@yegor256 19
mocking
algorithm
/38@yegor256 20
Book
BookTest
db
assumptions
/38@yegor256 21
Safety net.
(c) By John M, CC BY-SA 2.0
/38@yegor256 22
static import org.mockito.Mockito.*;
class BookTest {
@Test
public canFetchTitleFromDatabase() {
Database db = mock(Database.class);
doReturn(“UML Distilled”).when(db).fetch(
“SELECT title FROM book WHERE id=?”, 123
);
Book book = new Book(db, 123);
assert book.title().equals(“UML Distilled”);
}
}
class Book {
private int id;
private Database database;
Book(Database db, int i) {
this.database = db;
this.id = i;
}
String title() {
return this.database.fetch(
“SELECT title FROM book WHERE id=?”,

this.id
);
}
}
/38@yegor256 23
False positives.
/38@yegor256 24
Fakes or doubles.
/38@yegor256 25
class BookTest {
@Test
public canFetchTitleFromDatabase() {
Book book = new Book(
new FakeDatabase(), 123
);
assert book.title().equals(“UML Distilled”);
}
}
class Book {
private int id;
private Database database;
Book(Database db, int i) {
this.database = db;
this.id = i;
}
String title() {
return this.database.fetch(
“SELECT title FROM book WHERE id=?”,

this.id
);
}
}
/38@yegor256 26
class BookTest {
@Test
public canFetchTitleFromDatabase() {
Book book = new Book(
new FakeDatabase()
.withTitle(123, “UML Distilled”)
.withTitle(1, “Elegant Objects”)
.withUser(“Peter Pan”),
123
);
assert book.title().equals(“UML Distilled”);
}
}
/38@yegor256 27
Ad hoc mocking.
Fakes.
/38@yegor256
Algorithms
28
are evil
In-method
Maybe!
/38@yegor256 29
cactoos
www.cactoos.org
/38@yegor256 30
class BookTest {
@Test
public canBuildURL() {
Book book = new Book();
book.setLanguage(Locale.RUSSIAN);
book.setEncoding(“UTF-8”);
book.setTitle(“Дон Кихот”);
assert book.getURL().contains(“%D0%94%”);
}
}
procedural!
/38@yegor256 31
Hamcrest
An anagram for “matchers”.
/38@yegor256 32
A test method must have nothing
but a single statement:
assertThat()
/38@yegor256 33
assertThat(book, hasTitle(“UML Distilled”));
“We assert that the book behaves as if it has a title.”
/38@yegor256 34
assertThat(
book,
hasURL(
hasPath(
containsString(
equalTo(“%D0%94%”)
)
)
)
);
We assert that

the book behaves as if
it has a URL that behaves as if
it has a path that behaves as if
it contains a string that behaves as if
it is equal to “%D0%94%”.
/38@yegor256 35
/38@yegor256 36
/38@yegor256 37
shorter test methods
why?!
immutable objects
share matchers
/38@yegor256 38
Quality Award.
$4096

Object-Oriented JUnit Tests