built-in fake objects
TRANSCRIPT
/29@yegor256 1
Built-in Fake Objects
Yegor Bugayenko
/29@yegor256 2
“Mock objects are simulated objects that mimic the behavior of
real objects in controlled ways”
/29@yegor256 3
FakeObjects
Mocking Frameworks
/29@yegor256 4
static String report(User user) { return String.format( “Balance of %s is %d USD”, user.profile().name(), user.account().balance().usd() ); }
/29@yegor256 5
interface Profile { String name(); }
interface User { Profile profile(); Account account(); }
interface Account { Balance balance(); }
interface Balance { int usd(); }
/29@yegor256 6
@Test void printsReport() { User user = mock(User.class); assertThat( Foo.report(user), containsString(“Balance of”) ); }
Mockito
/29@yegor256 7@Test void printsReport() { Profile profile = mock(Profile.class); Account account = mock(Account.class); doReturn(“Jeffrey”).when(account).name(); Balance balance = mock(Balance.class); doReturn(123).when(balance).usd(); doReturn(balance).when(account).balance(); User user = mock(User.class); doReturn(profile).when(user).profile(); doReturn(account).when(user).account(); assertThat( Foo.report(user), containsString(“Balance of Jeffrey is 123 USD”) ); }
/29@yegor256 8
1. verbosity
/29@yegor256 9
@Test void printsReport() { Profile profile = mock(Profile.class); Account account = mock(Account.class); doReturn(“Jeffrey”).when(account).name(); Balance balance = mock(Balance.class); doReturn(123).when(balance).usd(); doReturn(balance).when(account).balance(); User user = mock(User.class); doReturn(profile).when(user).profile(); doReturn(account).when(user).account(); assertThat( Foo.report(user), containsString(“Balance of Jeffrey is 123 USD”) ); }
String report(User user) { return String.format( “Balance of %s is %d USD”, user.profile().name(), user.account().balance().usd() ); }
/29@yegor256 10
2. code duplication
/29@yegor256 11
@Test void reportIncludesUserName() { Profile profile = mock(Profile.class); Account account = mock(Account.class); doReturn(“Jeffrey”).when(account).name(); Balance balance = mock(Balance.class); doReturn(balance).when(account).balance(); User user = mock(User.class); doReturn(profile).when(user).profile(); doReturn(account).when(user).account(); assertThat( Foo.report(user), containsString(“Jeffrey”) ); }
@Test void reportIncludesBalanceInUSD() { Profile profile = mock(Profile.class); Account account = mock(Account.class); Balance balance = mock(Balance.class); doReturn(123).when(balance).usd(); doReturn(balance).when(account).balance(); User user = mock(User.class); doReturn(profile).when(user).profile(); doReturn(account).when(user).account(); assertThat( Foo.report(user), containsString(“123 USD”) ); }
/29@yegor256 12
3. complexity
/29@yegor256 13
example!!
/29@yegor256 14
4. fragility
because
of coupl
ing
/29@yegor256 15
@Test void printsReport() { Profile profile = mock(Profile.class); Account account = mock(Account.class); doReturn(“Jeffrey”).when(account).name(); Balance balance = mock(Balance.class); doReturn(123).when(balance).usd(); doReturn(balance).when(account).balance(); User user = mock(User.class); doReturn(profile).when(user).profile(); doReturn(account).when(user).account(); assertThat( Foo.report(user), containsString(“Balance of Jeffrey is 123 USD”) ); }
String report(User user) { return String.format( “Balance of %s is %d USD”, user.profile().name(), user.account().balance().usd() ); }
/29@yegor256 16
@Test void printsReport() { Profile profile = mock(Profile.class); Account account = mock(Account.class); doReturn(“Jeffrey”).when(account).name(); Balance balance = mock(Balance.class); doReturn(123).when(balance).usd(); doReturn(balance).when(account).balance(); User user = mock(User.class); doReturn(profile).when(user).profile(); doReturn(account).when(user).account(); assertThat( Foo.report(user), containsString(“Balance of Jeffrey is 123 USD”) ); }
String report(User user) { return String.format( “Balance of %s is %d USD”, user.profile().name(), user.account().usd() ); }
/29@yegor256 17
“Unit tests are your safety net”
/29@yegor256 18
false positive
/29@yegor256 19
throw-away tests
/29@yegor256 20
a solution?fake objects!
/29@yegor256 21
interface User { Profile profile(); Account account(); class Fake { Fake(String name, int balance) { // ... } // ... } }
/29@yegor256 22
@Test void printsReport() { User user = new User.Fake(“Jeffrey”, 123); assertThat( Foo.report(user), containsString(“Balance of Jeffrey is 123 USD”) ); }
verbosity?
/29@yegor256 23
@Test void reportIncludesUserName() { User user = new User.Fake(“Jeffrey”); assertThat( Foo.report(user), containsString(“Jeffrey”) ); }
code duplication?
@Test void reportIncludesBalanceInUSD() { User user = new User.Fake(123); assertThat( Foo.report(user), containsString(“123 USD”) ); }
/29@yegor256 24
@Test void reportIncludesUserName() { User user = new User.Fake(“Jeffrey”); assertThat( Foo.report(user), containsString(“Jeffrey”) ); }
complexity?
@Test void reportIncludesBalanceInUSD() { User user = new User.Fake(123); assertThat( Foo.report(user), containsString(“123 USD”) ); }
/29@yegor256 25
String report(User user) { return String.format( “Balance of %s is %d USD”, user.profile().name(), user.account().balance().usd() ); }
fragility?
@Test void reportIncludesBalanceInUSD() { User user = new User.Fake(123); assertThat( Foo.report(user), containsString(“123 USD”) ); }
/29@yegor256 26
no throw-away tests any more
/29@yegor256 27
always ship themtogether!
/29@yegor256 28
interface User { Profile profile(); Account account(); class Fake { } }
class UserTest { @Test void hasBalance() { User user = new User.Fake(123); assertThat( user.account().balance().usd(), not(equalTo(0)) ); } }
/29@yegor256 29
FakeObjects
Mocking Frameworks
/29@yegor256 30
Section 2.8
Don’t mock; use fakes