JUnit and Mockito tips
Mockito annotations
• @Mock
• @InjectMocks
• @Captor
Example production code
class MailServer {
void send(String smtpMessage) throws IOException {
// Opens a connection to a SMTP server, sends smtpMessage
}
}
class Messenger {
private final MailServer mailServer;
Messenger(MailServer mailServer) {
this.mailServer = mailServer;
}
void sendMail(String from, String to, String body) {
String smtpMessage = String.join("n", "From: " + from, "To: " + to, "", body);
try {
mailServer.send(smtpMessage);
} catch (IOException e) {
throw new UncheckedIOException("Error! smtpMessage=" + smtpMessage, e);
}
}
}
Test without Mockito annotations
class MessengerPlainTest {
MailServer mailServer;
Messenger sut;
@BeforeEach
void setUp() {
mailServer = Mockito.mock(MailServer.class);
sut = new Messenger(mailServer);
}
@Test
@DisplayName("Messenger constructs the SMTP message and feeds MailServer")
void test() throws IOException {
String expected = "From: joe@example.comn"
+ "To: jane@example.comnn"
+ "Hello!";
sut.sendMail("joe@example.com", "jane@example.com", "Hello!");
Mockito.verify(mailServer).send(expected);
}
}
Test with @Mock
@ExtendWith(MockitoExtension.class)
class MessengerTest {
@Mock
MailServer mailServer;
@InjectMocks
Messenger sut;
@Test
@DisplayName("Messenger constructs the SMTP message and feeds MailServer")
void test() throws IOException {
String expected = "From: joe@example.comn"
+ "To: jane@example.comnn"
+ "Hello!";
sut.sendMail("joe@example.com", "jane@example.com", "Hello!");
Mockito.verify(mailServer).send(expected);
}
}
Avoid unchecked assignment warning with
@Mock
Consumer<String> consumer = Mockito.mock(Consumer.class);
// The above yields:
Warning:(35, 49) java: unchecked conversion required:
java.util.function.Consumer<java.lang.String> found: java.util.function.Consumer
// Solution:
@ExtendWith(MockitoExtension.class)
class MyTest {
@Mock
Consumer<String> consumer;
...
Test with @Captor
@ExtendWith(MockitoExtension.class)
class MessengerCaptorTest {
@Mock
MailServer mailServer;
@InjectMocks
Messenger sut;
@Captor
ArgumentCaptor<String> captor;
@Test
@DisplayName("Messenger constructs the SMTP message and feeds MailServer")
void test() throws IOException {
sut.sendMail("joe@example.com", "jane@example.com", "Hello!");
Mockito.verify(mailServer).send(captor.capture());
String capturedValue = captor.getValue();
assertTrue(capturedValue.endsWith("Hello!"));
}
}
AssertJ
• A modern assertion library for unit tests written in Java
• Provides better readability and richer assertions than old equivalents
• https://assertj.github.io/doc/#assertj-overview
AssertJ examples (taken from here)
// basic assertions
assertThat(frodo.getName()).isEqualTo("Frodo");
assertThat(frodo).isNotEqualTo(sauron);
// chaining string specific assertions
assertThat(frodo.getName()).startsWith("Fro")
.endsWith("do")
.isEqualToIgnoringCase("frodo");
// collection specific assertions (there are plenty more)
// in the examples below fellowshipOfTheRing is a
List<TolkienCharacter>
assertThat(fellowshipOfTheRing).hasSize(9)
.contains(frodo, sam)
.doesNotContain(sauron);
AssertJ example for an unhappy path
@ExtendWith(MockitoExtension.class)
class MessengerUnhappyTest {
@Mock
MailServer mailServer;
@InjectMocks
Messenger sut;
@Test
@DisplayName("Messenger throws UncheckedIOException with the SMTP message when MailServer has thrown IOException")
void test() throws IOException {
doThrow(new IOException("The server is down")).when(mailServer).send(any());
String expectedMessage = "From: joe@example.comn"
+ "To: jane@example.comnn"
+ "Hello!";
assertThatThrownBy(() -> sut.sendMail("joe@example.com", "jane@example.com", "Hello!"))
.isInstanceOf(UncheckedIOException.class)
.hasMessage("Error! smtpMessage=%s", expectedMessage)
.hasCauseInstanceOf(IOException.class);
}
}
Conclusion
• We’ve discussed some tips about
• Mockito annotations
• Basic usages of AssertJ
• Recommended further reading:
• Mockito framework site
• AssertJ - fluent assertions java library
• Practical Unit Testing: JUnit 5, Mockito, TestNG, AssertJ - book by Tomek
Kaczanowski
• Code used in the slides: https://github.com/nuzayats/junittips

JUnit and Mockito tips

  • 1.
  • 2.
    Mockito annotations • @Mock •@InjectMocks • @Captor
  • 3.
    Example production code classMailServer { void send(String smtpMessage) throws IOException { // Opens a connection to a SMTP server, sends smtpMessage } } class Messenger { private final MailServer mailServer; Messenger(MailServer mailServer) { this.mailServer = mailServer; } void sendMail(String from, String to, String body) { String smtpMessage = String.join("n", "From: " + from, "To: " + to, "", body); try { mailServer.send(smtpMessage); } catch (IOException e) { throw new UncheckedIOException("Error! smtpMessage=" + smtpMessage, e); } } }
  • 4.
    Test without Mockitoannotations class MessengerPlainTest { MailServer mailServer; Messenger sut; @BeforeEach void setUp() { mailServer = Mockito.mock(MailServer.class); sut = new Messenger(mailServer); } @Test @DisplayName("Messenger constructs the SMTP message and feeds MailServer") void test() throws IOException { String expected = "From: joe@example.comn" + "To: jane@example.comnn" + "Hello!"; sut.sendMail("joe@example.com", "jane@example.com", "Hello!"); Mockito.verify(mailServer).send(expected); } }
  • 5.
    Test with @Mock @ExtendWith(MockitoExtension.class) classMessengerTest { @Mock MailServer mailServer; @InjectMocks Messenger sut; @Test @DisplayName("Messenger constructs the SMTP message and feeds MailServer") void test() throws IOException { String expected = "From: joe@example.comn" + "To: jane@example.comnn" + "Hello!"; sut.sendMail("joe@example.com", "jane@example.com", "Hello!"); Mockito.verify(mailServer).send(expected); } }
  • 6.
    Avoid unchecked assignmentwarning with @Mock Consumer<String> consumer = Mockito.mock(Consumer.class); // The above yields: Warning:(35, 49) java: unchecked conversion required: java.util.function.Consumer<java.lang.String> found: java.util.function.Consumer // Solution: @ExtendWith(MockitoExtension.class) class MyTest { @Mock Consumer<String> consumer; ...
  • 7.
    Test with @Captor @ExtendWith(MockitoExtension.class) classMessengerCaptorTest { @Mock MailServer mailServer; @InjectMocks Messenger sut; @Captor ArgumentCaptor<String> captor; @Test @DisplayName("Messenger constructs the SMTP message and feeds MailServer") void test() throws IOException { sut.sendMail("joe@example.com", "jane@example.com", "Hello!"); Mockito.verify(mailServer).send(captor.capture()); String capturedValue = captor.getValue(); assertTrue(capturedValue.endsWith("Hello!")); } }
  • 8.
    AssertJ • A modernassertion library for unit tests written in Java • Provides better readability and richer assertions than old equivalents • https://assertj.github.io/doc/#assertj-overview
  • 9.
    AssertJ examples (takenfrom here) // basic assertions assertThat(frodo.getName()).isEqualTo("Frodo"); assertThat(frodo).isNotEqualTo(sauron); // chaining string specific assertions assertThat(frodo.getName()).startsWith("Fro") .endsWith("do") .isEqualToIgnoringCase("frodo"); // collection specific assertions (there are plenty more) // in the examples below fellowshipOfTheRing is a List<TolkienCharacter> assertThat(fellowshipOfTheRing).hasSize(9) .contains(frodo, sam) .doesNotContain(sauron);
  • 10.
    AssertJ example foran unhappy path @ExtendWith(MockitoExtension.class) class MessengerUnhappyTest { @Mock MailServer mailServer; @InjectMocks Messenger sut; @Test @DisplayName("Messenger throws UncheckedIOException with the SMTP message when MailServer has thrown IOException") void test() throws IOException { doThrow(new IOException("The server is down")).when(mailServer).send(any()); String expectedMessage = "From: joe@example.comn" + "To: jane@example.comnn" + "Hello!"; assertThatThrownBy(() -> sut.sendMail("joe@example.com", "jane@example.com", "Hello!")) .isInstanceOf(UncheckedIOException.class) .hasMessage("Error! smtpMessage=%s", expectedMessage) .hasCauseInstanceOf(IOException.class); } }
  • 11.
    Conclusion • We’ve discussedsome tips about • Mockito annotations • Basic usages of AssertJ • Recommended further reading: • Mockito framework site • AssertJ - fluent assertions java library • Practical Unit Testing: JUnit 5, Mockito, TestNG, AssertJ - book by Tomek Kaczanowski • Code used in the slides: https://github.com/nuzayats/junittips