1

I can't find a solution that will help me test my ViewModels. I keep reading that it's enough to add rule :

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

but I keep getting :

java.lang.RuntimeException: Method getMainLooper in android.os.Looper not mocked. See http://g.co/androidstudio/not-mocked for details.

My test class looks like this now :

@RunWith(MockitoJUnitRunner::class)
class MainActivityViewModelTest {

@get:Rule
val taskExecutorRule = InstantTaskExecutorRule()

val weatherProviderMock = mock<WeatherProvider>()
val sut = MainActivityViewModel(weatherProviderMock, mock(), mock(),     mock())

    @Test
    fun shouldPass() {
        assertTrue(true)
    }
}

I also have the following in my app build.gradle:

testImplementation 'junit:junit:4.12'
testImplementation "android.arch.core:core-testing:1.1.1"
testImplementation 'org.mockito:mockito-core:2.22.0'
testImplementation 'org.assertj:assertj-core:3.9.1'
testImplementation 'com.nhaarman:mockito-kotlin:1.6.0'
testImplementation 'org.mockito:mockito-inline:2.22.0'

Any help much appreciated.

@Chris

Can you please tell me if there's anything wrong with the code below (as per your proposed solutions):

lateinit var sut: SummaryViewModel
@get:Rule
val rule: TestRule = InstantTaskExecutorRule()

@Before
fun setUp() {
    sut = SummaryViewModel(calculatorMock, mock(), mock(), mock(), providerMock, mock())
}

@Test
fun `live data test`() {
    val someLiveData = sut.someLiveDataValue
    assertThat(true).isTrue()
}
  • 1
    What does your MainActivityViewModel do in it's constructor? – Chris Oct 18 '18 at 09:41
  • @Chris, I've made some operations on LiveData in the constructor. I still don't know what the issue with this is, but apparently moving this out from constructor made the test to pass and looper to be mocked. One more thing worth mentioning here is that the `ViewModel` is in Java and tests are kotlin, not sure how could that affect the mocking but maybe? Any idea? – Krzysztof Kubicki Oct 18 '18 at 10:04
  • 2
    If your ViewModel is interacting with LiveData in its constructor you'll need to delay the creation of your ViewModel until the rule has been executed. You could for example declare the ViewModel as a lateinit property and use the @Before annotation to create it in a setup method with any configured mocks. – Chris Oct 18 '18 at 12:08
  • @Chris - I've posted a solution based on your comment, would you please take a look it's in the updated question at the bottom. – Krzysztof Kubicki Oct 22 '18 at 08:25
  • 1
    Do you still get the looper issue? – Chris Oct 24 '18 at 08:42
  • @Chris - your solutions works, but isn't `@Before` called before every `@Test` method? Btw -> add an answer so I can mark it as accepted. – Krzysztof Kubicki Feb 07 '19 at 12:53
  • Possible duplicate of [setValue and postValue on MutableLiveData in UnitTest](https://stackoverflow.com/questions/45988310/setvalue-and-postvalue-on-mutablelivedata-in-unittest) – AdamHurwitz Sep 08 '19 at 17:00

2 Answers2

0

You could lazily initialize the ViewModel using Kotlin delegates:

    val viewModel by lazy { 
        MainActivityViewModel(weatherProviderMock, mock(), mock()...)
    }
nebulasmoothie
  • 371
  • 3
  • 7
0

In case none of the solutions worked alike in my case, if you are using a later version of Gradle and you are using androix, make sure you import from androix in your build gradle.

implementation 'androidx.arch.core:core-testing:$version'

instead of

implementation 'android.arch.core:core-testing:$version'

Liz
  • 41
  • 6