Upgrade to Pro — share decks privately, control downloads, hide ads and more …

JUnit Day

JUnit Day

In February 16th, 2006, the library known as JUnit 4 is released.

JUnit4 is adopted quickly, and in geometric rate takes control of all unit testing in JAVA.

In September 10th of 2017, the Resistance sends back in time a reprogrammed version of JUnit to protect humanity.

This day is known as JUnit5 Day.

Saúl Díaz

April 14, 2021
Tweet

More Decks by Saúl Díaz

Other Decks in Programming

Transcript

  1. In September 10th of 2017, the Resistance sends back in

    time a reprogrammed version of JUnit to protect humanity _
  2. JUNIT 5 STRUCTURE JUnit 5 Platform JUnit 5 Jupiter JUnit

    5 Launcher JUnit 5 Params JUnit 5 Vintage
  3. TOUCH THE LAND RUNNING Replace With import org.junit.Test import org.junit.jupiter.api.Test

    import org.junit.Before import org.junit.jupiter.api.BeforeEach @Before @BeforeEach import org.junit.After import org.junit.jupiter.api.AfterEach @After @AfterEach import org.junit.BeforeClass import org.junit.jupiter.api.BeforeAll @BeforeClass @BeforeAll import org.junit.AfterClass import org.junit.jupiter.api.AfterAll @AfterClass @AfterAll import org.junit.Ignore import org.junit.jupiter.api.Disabled @Ignore @Disabled
  4. NO MORE RUNNERS @RunWith(MockitoJUnitRunner::class) class JUnit4RunnerTest { @Mock lateinit var

    mock : UserDao @Test fun `Whatever random test this is`() { /.../ } }
  5. USING MOCKITO EXTENSION @ExtendWith(MockitoExtension::class) @MockitoSettings(strictness = LENIENT) class JUnit5ExtensionTest {

    @Mock lateinit var mock : UserDao @Test fun `Whatever random test this is`() { /.../ } }
  6. HOW TO DEFINE AN EXTENSION class UTCExtension : BeforeEachCallback, AfterEachCallback

    { private lateinit var originalTimeZone: TimeZone override fun beforeEach(context: ExtensionContext?) { originalTimeZone = TimeZone.getDefault() TimeZone.setDefault(TimeZone.getTimeZone("UTC")) } override fun afterEach(context: ExtensionContext?) { TimeZone.setDefault(originalTimeZone) } }
  7. HOW TO DEFINE AN EXTENSION AfterAllCallback AfterEachCallback AfterEachMethodAdapter AfterTestExecutionCallback BeforeAllCallback

    BeforeEachCallback BeforeEachMethodAdapter BeforeTestExecutionCallback ExecutionCondition InvocationInterceptor LifecycleMethodExecutionExceptionHandler ParameterResolver TestExecutionExceptionHandler TestInstanceFactory TestInstancePostProcessor TestInstancePreDestroyCallback TestTemplateInvocationContextProvider TestWatcher
  8. CHECKING FOR EXCEPTIONS // Java @Test public void throwsUnauthorizedException() throws

    Exception { enqueueMockResponseFromFile(401, "common/errors/error-unauthorized.json") assertThrows(UnauthorizedException.class, () -> apiClient.get("id")); } // Kotlin @Test fun `Throws unauthorized exception`() { enqueueMockResponseFromFile(401, "common/errors/error-unauthorized.json") assertThrows<UnauthorizedException> { apiClient.get("id") } }
  9. Parallel enabled false true Classes default Same thread Concurrent Same

    thread Concurrent fixed dynamic Mode default strategy Disable parallelism Enable parallelism Execute test classes sequentially Parallelize test classes Execute test methods sequentially Parallelize test methods Fixed number of threads Dynamic number of threads
  10. PARALELLIZING THE STAGE class A { @Test fun test1() {...}

    @Test fun test2() {...} } class B { @Test fun test1() {...} @Test fun test2() {...} }
  11. COMPARISON BETWEEN CONFIGS A.test1 A.test2 B.test1 B.test2 A.test1 B.test1 A.test2

    B.test2 A.test1 A.test2 B.test1 B.test2 A.test1 A.test2 B.test1 B.test2 Class: concurrent Method: same_thread Class: same_thread Method: concurrent Class: concurrent Method: concurrent Class: same_thread Method: same_thread
  12. EASING THE DRAWBACKS OF PARALELLIZING @ExtendWith(UTCExtension::class, LocaleExtension::class) @ResourceLocks( ResourceLock(TIME_ZONE, mode

    = READ_WRITE), ResourceLock(LOCALE, mode = READ_WRITE) ) class ParallelTestWhichUsesTZAndLocale { /*...*/ }
  13. EASING THE DRAWBACKS OF PARALELLIZING @Isolated @ExtendWith(UserAgentExtension::class) open class MockWebServerTest

    : RecordedRequests { protected lateinit var server: MockWebServer @BeforeEach open fun setUp() { this.server = MockWebServer() this.server.start() } /.../ }
  14. NORMAL TESTS class ApiExceptionMapperTest { @Test fun `Throws Network exception

    when receiving a 400 status code`() @Test fun `Throws Network exception when receiving a 412 status code`() @Test fun `Throws Network exception when receiving a 418 status code`() @Test fun `Throws Network exception when receiving a 500 status code`() }
  15. PARAMETRIC TESTS class ApiExceptionMapperTest { @ParameterizedTest(name = "Throws Network Exception

    when receiving {0} status code") @ValueSource( ints = [ HttpStatus.SC_BAD_REQUEST, HttpStatus.SC_REQUEST_TOO_LONG, HttpStatus.SC_IM_A_TEAPOT, HttpStatus.SC_INTERNAL_SERVER_ERROR ] ) fun `Throws Newtork Exception when receiving code `(status: Int) }
  16. TYPES OF DATA @ValueSource @ParameterizedTest @NullSource @EmptySource @NullAndEmptySource short byte

    int long float double char String Class @EnumSource @MethodSource
  17. MORE COMPLICATED PARAMETRIC TESTS class FieldTypeMapperTest { @Test fun `Parses

    correctly string phone number subtype`() { val result = mapper.map("string", "phone number") result shouldBe FieldType.PHONE } }
  18. MORE COMPLICATED PARAMETRIC TESTS class FieldTypeMapperTestParameter( val type: String, val

    hint: String, val expectation: FieldType ) private companion object { @JvmStatic fun fieldTypeTestProvider() = listOf( FieldTypeMapperTestParameter("string", "phone-number", FieldType.PHONE), /.../ ) }
  19. MORE COMPLICATED PARAMETRIC TESTS class FieldTypeMapperTest { @ParameterizedTest @MethodSource("fieldTypeTestProvider") fun

    `Parses correctly field`(parameter: FieldTypeMapperTestParameter) { val result = mapper.map(parameter.type, parameter.hint) assertEquals(parameter.expectation, result) } /.../ }
  20. TEST TAGGING @Tag("core") @Tag("domain") class LoginUseCaseTest { @Tag("login") @Test fun

    `Performs login successfully when the credentials are correct`() @Tag("login") @Tag("error case") @Test fun `Returns error when receiving incorrect credentials`() }
  21. NESTED TESTS @DisplayName("Login") class LoginUseCaseTest { @DisplayName("performs successfully when the

    credentials are correct") @Test fun `Performs login successfully when the credentials are correct`() @DisplayName("returns error") class OnErrors { @DisplayName("when receiving incorrect credentials") @Test fun `Returns error when receiving incorrect credentials`() @DisplayName("when server is down") @Test fun `Returns error when server is down`() } }