Can't start junit test when application class is customized

825 views Asked by At

When I try to start one of my junit tests, all of them fail due to multiple errors. This is due to the fact, that my Application class has some variables in it, which are initialized in the "normal" app start, but not when I start a test. Commenting the variables out might help, but that is an ugly solution, to always comment stuff out, when starting a test.

Application Class

@HiltAndroidApp
@InternalCoroutinesApi
class App : Application(), Configuration.Provider {
    @Inject lateinit var workerFactory: HiltWorkerFactory
    @Inject lateinit var workerList: WorkerList
    override fun onCreate() {
        super.onCreate()
        plantTimberTree()
        enableOfflinePersistence()
        workerList.startDownloadDocumentWork()
    }

    override fun getWorkManagerConfiguration(): Configuration =
        Configuration.Builder().setWorkerFactory(workerFactory).build()
}

private fun plantTimberTree() = Timber.plant(Timber.DebugTree())

private fun enableOfflinePersistence() {
    val settings = firestoreSettings { isPersistenceEnabled = true }
    Firebase.firestore.firestoreSettings = settings
}

TestCase

@RunWith(RobolectricTestRunner::class)
@Config(maxSdk = Build.VERSION_CODES.P, minSdk = Build.VERSION_CODES.P)
class EmailViewModelTest {


}

Error Stacktrace (without any comment)

java.lang.IllegalStateException: Default FirebaseApp is not initialized in this process null. Make sure to call FirebaseApp.initializeApp(Context) first.

    at com.google.firebase.FirebaseApp.getInstance(FirebaseApp.java:184)
    at com.google.firebase.firestore.FirebaseFirestore.getInstance(FirebaseFirestore.java:91)
    at com.google.firebase.firestore.ktx.FirestoreKt.getFirestore(Firestore.kt:32)
    at com.example.app.AppKt.enableOfflinePersistence(App.kt:44)
    at com.example.app.AppKt.access$enableOfflinePersistence(App.kt:1)
    at com.example.app.App.onCreate(App.kt:24)
    at org.robolectric.android.internal.AndroidTestEnvironment.lambda$installAndCreateApplication$0(AndroidTestEnvironment.java:288)
    at org.robolectric.util.PerfStatsCollector.measure(PerfStatsCollector.java:75)
    at org.robolectric.android.internal.AndroidTestEnvironment.installAndCreateApplication(AndroidTestEnvironment.java:288)
    at org.robolectric.android.internal.AndroidTestEnvironment.setUpApplicationState(AndroidTestEnvironment.java:171)
    at org.robolectric.RobolectricTestRunner.beforeTest(RobolectricTestRunner.java:319)
    at org.robolectric.internal.SandboxTestRunner$2.lambda$evaluate$0(SandboxTestRunner.java:254)
    at org.robolectric.internal.bytecode.Sandbox.lambda$runOnMainThread$0(Sandbox.java:89)
    at java.util.concurrent.FutureTask.run(FutureTask.java:266)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
    at java.lang.Thread.run(Thread.java:748)

Error Stacktrace (when commenting "enableOfflicePersistence" out)

kotlin.UninitializedPropertyAccessException: lateinit property workerList has not been initialized

    at com.example.app.App.onCreate(App.kt:25)
    at org.robolectric.android.internal.AndroidTestEnvironment.lambda$installAndCreateApplication$0(AndroidTestEnvironment.java:288)
    at org.robolectric.util.PerfStatsCollector.measure(PerfStatsCollector.java:75)
    at org.robolectric.android.internal.AndroidTestEnvironment.installAndCreateApplication(AndroidTestEnvironment.java:288)
    at org.robolectric.android.internal.AndroidTestEnvironment.setUpApplicationState(AndroidTestEnvironment.java:171)
    at org.robolectric.RobolectricTestRunner.beforeTest(RobolectricTestRunner.java:319)
    at org.robolectric.internal.SandboxTestRunner$2.lambda$evaluate$0(SandboxTestRunner.java:254)
    at org.robolectric.internal.bytecode.Sandbox.lambda$runOnMainThread$0(Sandbox.java:89)
    at java.util.concurrent.FutureTask.run(FutureTask.java:266)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
    at java.lang.Thread.run(Thread.java:748)

Is there a way to determine, whether a test has been started or not? How should I change my Application class in order to get my tests running again?

I appreciate every help, thank you.

2

There are 2 answers

8
AndroidNoob On

This can be solved by implementing Roboelectric library as it provides the android environment to run your tests.

Check the below link to get detailed description how to use it. I found it very useful.

https://codelabs.developers.google.com/codelabs/advanced-android-kotlin-training-testing-basics/#0

0
Turnsole On

I see you're using RobolectricTestRunner.

There's a couple different ways to solve the problem of FirebaseApp getting into weird states during a Robolectric test vs how it would behave if your Application class had been initialized normally.

(1) You can use Robolectric to specify a special test Application context to use that does whatever you want with Firebase.

(2) You can use Roboelectric to create a shadow class for FirebaseApp that behaves in whatever way you desire. (Here's one example in which I have the shadow class catch that exception you referenced and initialize Firebase.)

The advantage of writing a shadow class for FirebaseApp is that it can be configured to intervene for any way your code may access FirebaseApp, and a robolectric.properties file can configure your whole test package.