Android Unit Test Using Junit 5

2 minute read

Unit Test

In the Testing is Part of Android Development already define what is Unit Test. Better read it before continue this article.

For remaind you, Unit Test have definition are :

  1. Focus tests isolate one class​.
  2. Assume class dependencies are already working correctly​.
  3. Independent from Android framework / third party​.
  4. Run under JVM.

Overview

For this part will be guide you to Combine Junit4 and Junit5. Android as default using JUnit 4, but if we want to get more feature from JUnit5 why not?.

Step by step

Add Junit 4 and Junit 5 to Android Project

this configuration on app/build.gradle:

 1
 2plugins {
 3  id "de.mannodermaus.android-junit5" version "1.8.2.1"
 4}
 5
 6dependencies {
 7
 8    //Junit5
 9    testImplementation "org.junit.jupiter:junit-jupiter-api:5.8.2"
10    testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:5.8.2"
11
12    // (Optional) if you need "Parameterized Tests"
13    testImplementation "org.junit.jupiter:junit-jupiter-params:5.8.2"
14
15    //Junit4
16    testImplementation "junit:junit:4.13.2"
17    testRuntimeOnly "org.junit.vintage:junit-vintage-engine:5.8.2"
18}

this configuration on /build.gradle:

1buildscript {
2  dependencies {
3    classpath "de.mannodermaus.android-junit5:1.8.2.1"
4  }
5}

Detail docummentation please see android-junit5.

JVM test only

I assume this unit test run on the JVM, no Robolectic or Android. Please add on app/build.gradle:

1
2android {
3    testOptions {
4        unitTests.all {
5            useJunitPlatform()
6        }
7    }
8}

Let’s writting the test

This part will be written by Junit4. We test UserRepository class, the class have dependecies to UserLocalDataSource and UserRemoteDataSource. I mocking the dependecies using Mockk.io. if you see comments, i’m describe what we need changes.

 1// we do not need @RunWith because it's replaced by @ExtendWith. ​
 2class UserRepositoryTest {​
 3
 4    private val local: UserLocalDataSource​ = mockk()
 5
 6    private val remote: UserRemoteDataSource​ = mockk()
 7
 8    private val repository: UserRepository​ = UserRepository(local, remote)​
 9
10
11    // @Before and @After replaced with @BeforeEach and @AfterEach​
12    @Before​
13    fun setup() {​
14        clearMock(local, remote)
15    }​
16
17    @After​
18    fun tear() {​
19    }​
20
21    // Use @Test from org.junit.jupiter.api.Test instead of org.junit.Test​
22    @Test​
23    fun `When repository no local then query to remote then should be success`(){​
24    }​
25
26    // If we want to group several test cases, use @Nested for grouping​
27    @Nested​
28    inner class LocalDataSourceSpec {​
29    }​
30}​
  1. Change the import

If we use JUnit5 don’t forget changing import for @Test

1// Before
2import org.junit.Test  
3
4// After
5import org.junit.jupiter.api.Test  
  1. @Before replace to @BeforeEach

Junit5 have lifecycle each function or class, I’m prefer using each function. so every test in function before run it will trigger @BeforeEach.

  1. @After replace to @AfterEach

That are same like @BeforeEach, this is will be execute After one function done exacute the test.

  1. Grouping the test using @Nested

JUnit5 introduces @Nested, allowing you to group a set of tests into an inner class.