androidkotlinandroid-fragmentsandroid-safe-argsandroid-fragmentscenario

fragment arguments are null using launchFragmentInContainer


I am writing a test for a fragment that uses safeArgs and FragmentScenario, however when I call launchFragmentInContainer() with the fragmentArgs parameter, I get an exception saying the arguments are null. There is no problem in production code.

My navigation graph:

<fragment
        android:id="@+id/fragmentNewListItems"
        android:name="com.hotmail.or_dvir.arislistkt2.vvm.FragmentNewListItems"
        android:label="@string/title_newItems"
        tools:layout="@layout/fragment_new_list_items">

        <argument
            android:name="listId"
            app:argType="string" />
        <argument
            android:name="listName"
            app:argType="string" />
    </fragment>

My test:

class TesFragmentNewListItems : BaseAndroidTest() {
    private lateinit var fragScenario: FragmentScenario<FragmentNewListItems>

    private val list1 = UserList("list 1")

    @Before
    fun before() {
        //adding a user list to add items to
        repoUserLists.addLists(list1)
        fragScenario = this.launchFragment(
            //setting arguments here
            bundleOf("listId" to list1.id, "listName" to list1.name)
        )
    }


    inline fun <reified T : Fragment> launchFragment(args: Bundle): FragmentScenario<T> {
        return launchFragmentInContainer<T>(
            themeResId = R.style.AppTheme,
            fragmentArgs = args
        )
    }

when i try to run the test i get

Caused by: java.lang.IllegalArgumentException: Argument "listId" is marked as non-null but was passed a null value.

full stack trace:

java.lang.RuntimeException: java.lang.reflect.InvocationTargetException
at androidx.test.runner.MonitoringInstrumentation.runOnMainSync(MonitoringInstrumentation.java:441)
at androidx.test.core.app.ActivityScenario.onActivity(ActivityScenario.java:564)
at androidx.fragment.app.testing.FragmentScenario.internalLaunch(FragmentScenario.java:300)
at androidx.fragment.app.testing.FragmentScenario.launchInContainer(FragmentScenario.java:282)
at com.hotmail.or_dvir.arislistkt2.TesFragmentNewListItems.before(TesFragmentNewListItems.kt:79)
at java.lang.reflect.Method.invoke(Native Method)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at androidx.test.internal.runner.junit4.statement.RunBefores.evaluate(RunBefores.java:76)
at androidx.test.internal.runner.junit4.statement.RunAfters.evaluate(RunAfters.java:61)
at org.junit.rules.TestWatcher$1.evaluate(TestWatcher.java:55)
at org.koin.test.mock.MockProviderRule$apply$1.evaluate(MockProviderRule.kt:13)
at org.junit.rules.TestWatcher$1.evaluate(TestWatcher.java:55)
at org.junit.rules.RunRules.evaluate(RunRules.java:20)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.junit.runners.Suite.runChild(Suite.java:128)
at org.junit.runners.Suite.runChild(Suite.java:27)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at org.junit.runner.JUnitCore.run(JUnitCore.java:115)
at androidx.test.internal.runner.TestExecutor.execute(TestExecutor.java:56)
at androidx.test.runner.AndroidJUnitRunner.onStart(AndroidJUnitRunner.java:392)
at android.app.Instrumentation$InstrumentationThread.run(Instrumentation.java:2189)
Caused by: java.lang.reflect.InvocationTargetException
at java.lang.reflect.Method.invoke(Native Method)
at androidx.navigation.NavArgsLazy.getValue(NavArgsLazy.kt:52)
at androidx.navigation.NavArgsLazy.getValue(NavArgsLazy.kt:34)
at com.hotmail.or_dvir.arislistkt2.vvm.FragmentNewListItems.getFragArgs(Unknown Source:4)
at com.hotmail.or_dvir.arislistkt2.vvm.FragmentNewListItems.onViewCreated(FragmentNewListItems.kt:31)
at androidx.fragment.app.FragmentStateManager.createView(FragmentStateManager.java:332)
at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1199)
at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1368)
at androidx.fragment.app.FragmentManager.moveFragmentToExpectedState(FragmentManager.java:1446)
at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1509)
at androidx.fragment.app.BackStackRecord.executeOps(BackStackRecord.java:447)
at androidx.fragment.app.FragmentManager.executeOps(FragmentManager.java:2181)
at androidx.fragment.app.FragmentManager.executeOpsTogether(FragmentManager.java:2004)
at androidx.fragment.app.FragmentManager.removeRedundantOperationsAndExecute(FragmentManager.java:1959)
at androidx.fragment.app.FragmentManager.execSingleAction(FragmentManager.java:1830)
at androidx.fragment.app.BackStackRecord.commitNow(BackStackRecord.java:297)
at androidx.fragment.app.testing.FragmentScenario$1.perform(FragmentScenario.java:317)
at androidx.fragment.app.testing.FragmentScenario$1.perform(FragmentScenario.java:301)
at androidx.test.core.app.ActivityScenario.lambda$onActivity$2$ActivityScenario(ActivityScenario.java:551)
at androidx.test.core.app.ActivityScenario$$Lambda$4.run(Unknown Source:4)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:462)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at android.app.Instrumentation$SyncRunnable.run(Instrumentation.java:2207)
at android.os.Handler.handleCallback(Handler.java:883)
at android.os.Handler.dispatchMessage(Handler.java:100)
at android.os.Looper.loop(Looper.java:214)
at android.app.ActivityThread.main(ActivityThread.java:7356)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930)
Caused by: java.lang.IllegalArgumentException: Argument "listId" is marked as non-null but was passed a null value.
at com.hotmail.or_dvir.arislistkt2.vvm.FragmentNewListItemsArgs$Companion.fromBundle(FragmentNewListItemsArgs.kt:28)
at com.hotmail.or_dvir.arislistkt2.vvm.FragmentNewListItemsArgs.fromBundle(Unknown Source:2)
... 30 more

Edit:

The id of List1 is not null as it is initialized in the constructor.

class UserList(
    name: String
) : BaseItem(name) {

    //class body
}
abstract class BaseItem(
    var name: String,
    var id: UUID = UUID.randomUUID()
) {

    //class body
}

Solution

  • figured it out. i somehow missed this warning:

    W/Bundle: Key listId expected String but value was a java.util.UUID.  The default value <null> was returned.
    

    all i had to do was change this bundleOf("listId" to list1.id...) to bundleOf("listId" to list1.id.toString()...) (added call to toString())

    not sure why google chose to handle invalid types by turning them into null instead of throwing an "InvalidParameter" exception (or similar).