34

I want to write a unit test. Therefore I need MutableLiveData. I started with a very basic test for setup but I cannot instantiate a MutableLiveData object. I is always null when I run the test. Do I have to mock anything? Any suggestions?

@RunWith(MockitoJUnitRunner.class)
public class DefaultLiveDataTest {

    private static final int EXPECTED = 5;

    private final MutableLiveData<Integer> underTest = new MutableLiveData<>();


    @Test
    public void exampleTest() {

    underTest.setValue(EXPECTED); //underTest is Null
    assertEquals(underTest.getValue().intValue(), EXPECTED);

    }
}

java.lang.NullPointerException
at android.arch.core.executor.DefaultTaskExecutor.isMainThread(DefaultTaskExecutor.java:58)
at android.arch.core.executor.ArchTaskExecutor.isMainThread(ArchTaskExecutor.java:116)
at android.arch.lifecycle.LiveData.assertMainThread(LiveData.java:434)
at android.arch.lifecycle.LiveData.setValue(LiveData.java:279)
at android.arch.lifecycle.MutableLiveData.setValue(MutableLiveData.java:33)
at com.mypackage.DefaultLiveDataTest.test_that_live_data_has_default_value(DefaultLiveDataTest.java:22)

build.gradle

apply plugin: 'com.android.application'

android {
compileSdkVersion 27
defaultConfig {
    applicationId 'com.mypackage.title'
    minSdkVersion 16
    targetSdkVersion 27
    versionCode 1
    versionName '1.0'
    testInstrumentationRunner 'android.support.test.runner.AndroidJUnitRunner'
}

testOptions {
    unitTests.returnDefaultValues = true
}

dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'com.android.support:appcompat-v7:27.1.1'
implementation 'com.android.support:design:27.1.1'
implementation 'com.android.support.constraint:constraint-layout:1.0.2'
implementation 'com.android.support:support-vector-drawable:27.1.1'
implementation 'android.arch.lifecycle:extensions:1.1.1'
implementation 'android.arch.lifecycle:viewmodel:1.1.1'
implementation 'android.arch.lifecycle:livedata:1.1.1'

annotationProcessor 'android.arch.lifecycle:compiler:1.1.1'
testImplementation 'junit:junit:4.12'
testImplementation 'org.mockito:mockito-core:1.10.19'
androidTestImplementation 'com.android.support.test:runner:1.0.1'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1'
annotationProcessor 'org.androidannotations:androidannotations:4.4.0'
implementation 'org.androidannotations:androidannotations-api:4.4.0'
compileOnly 'org.projectlombok:lombok:1.16.20'
annotationProcessor 'org.projectlombok:lombok:1.16.20'
}
Braian Coronel
  • 22,105
  • 4
  • 57
  • 62
Kewitschka
  • 1,445
  • 1
  • 21
  • 35

3 Answers3

59

Looks like you are missing the android.arch.core:core-testing dependency.

testImplementation "android.arch.core:core-testing:1.1.1"

This allows you to use the InstantTaskExecutorRule in your test, which will get rid of the isMainThread call.

https://developer.android.com/reference/android/arch/core/executor/testing/InstantTaskExecutorRule.html

@Rule
public InstantTaskExecutorRule instantTaskExecutorRule = new InstantTaskExecutorRule();
Chris
  • 2,332
  • 1
  • 14
  • 17
  • Note, that if you still used mockito 1.x, this will force you to update to mockito 2.19 – Alexander Pacha Sep 25 '19 at 15:52
  • for androidx what will be dependency? – Anmol Oct 14 '19 at 06:19
  • 2
    For AndroidX it's currently `androidx.arch.core:core-testing:2.1.0`. Also note that the rule only seems to work with JUnit 4 but not with 5. – Michael Troger Oct 21 '19 at 13:37
  • Yes, for Junit 5 you would just create your own Extension. If it's nowhere yet on Stackoverflow then feel free to create a question and I can add the implementation of my custom extension. @SoH If you link the question here – Michael Troger May 04 '20 at 09:01
  • @MichaelTroger heres a link to my question: https://stackoverflow.com/questions/61582063/unit-testing-livedata-observerforever-results-in-nullpointer-exception-with-juni – SoH May 04 '20 at 13:15
  • yeah make sure its public! – Ahmad Shahwaiz Sep 19 '21 at 07:33
17

Add an executor InstantTaskExecutorRule() as a member of the Test class

A JUnit Test Rule that swaps the background executor used by the Architecture Components with a different one which executes each task synchronously. You can use this rule for your host side tests that use Architecture Components.

//@RunWith(JUnit4::class)   // For JUnit4
@ExtendWith(InstantExecutorExtension::class)   // For JUnit5
class FilterViewModelTest {

    @Rule @JvmField
    val instantTaskExecutorRule = InstantTaskExecutorRule()

    @Test
    fun test() {
        //Here you don't ask if isMainThread
    }
}

build.gradle(:mobile)

android {
    //...
    dependencies {
        //...
        testImplementation 'androidx.arch.core:core-testing:2.1.0'
        androidTestImplementation 'androidx.arch.core:core-testing:2.1.0'
    }
}

GL

InstantTaskExecutorRule

Braian Coronel
  • 22,105
  • 4
  • 57
  • 62
  • 2
    This is the more up-to-date answer. Thank you. – Xi Wei Jun 04 '20 at 18:45
  • 1
    I was missing `@RunWith(JUnit4::class)` and no other answer anywhere on internet mentioned that. Thank you friend. – rgv Jan 17 '21 at 03:01
  • 1
    For junit5 replace `@RunWith(JUnit4::class)` on top of the class with `@ExtendWith(InstantExecutorExtension::class)` and remove the val. – Siamak Nov 15 '21 at 21:13
6

I had this error and solved it by adding InstantTaskExecutorRule:

private lateinit var contactProfileViewModel: ContactProfileViewModel

private val getStatusesForContact: GetStatusesForContact = mockk(relaxed = true)
private val getStory: GetUserLastStory = mockk(relaxed = true)
private val successStatusesCaptor = slot<((List<StatusDomain>) -> Unit)>()
private val successStoryCaptor = slot<((List<StoryDomain>) -> Unit)>()

@get:Rule
val rule: TestRule = InstantTaskExecutorRule()

@Before
fun setUp(){
    contactProfileViewModel = ContactProfileViewModel(getStatusesForContact, getStory)
}
Iban Arriola
  • 2,526
  • 9
  • 41
  • 88