【问题标题】:Android mocking applicationcontext inside applicationAndroid在应用程序内模拟应用程序上下文
【发布时间】:2020-02-23 04:26:58
【问题描述】:

我在创建测试类时遇到问题。基本上我想测试执行网络调用的视图模型类。使用匕首注入的类网络组件需要上下文参数来检查连接,这是我的视图模型:

class MyViewModel(application: Application): AndroidViewModel(application) {
   @Inject lateinit var network: NetworkService
    init {
        DaggerNetworkComponent.builder().networkModule(NetworkModule(application.applicationContext))
        .build().inject(this)
        network.callNetwork()
    } 
}

而测试类是这样的

lateinit var myViewModel: MyViewModel
@Test
fun testMyNetwork() { 
   application =  Mockito.mock(Application::class.java)
   myViewModel = MyViewModel(application)
}

application.applicationContext 总是返回 null 然后返回 IllegalStateException

有什么解决办法吗?

【问题讨论】:

    标签: android unit-testing mockito android-viewmodel


    【解决方案1】:

    我认为这里有两种可能性。我使用了第二个并且知道它有效,第一个是我的猜测。

    (1)

    您正在模拟应用程序。然后你试图使用它的applicationContext 但是你没有嘲笑它。您还需要模拟它:

    val context  =  Mockito.mock(Context::class.java)
    Mockito.`when`(application.applicationContext).thenReturn(context)
    

    (2)

    假设 1) 您的测试是仪器测试 2) 您正在使用 Application 的子类 - 比如 MyApplication

    然后您必须创建它的子类 - 例如,TestMyApplication。下一步是创建AndroidJUnitRunner 的子类,可能是这样的:

    public class MyInstrumentationTestRunner extends AndroidJUnitRunner {
        @Override
        public Application newApplication(ClassLoader cl, String className, Context context)
                throws InstantiationException, IllegalAccessException, ClassNotFoundException {
            return Instrumentation.newApplication(TestMyApplication.class, context);
        }
    }
    

    最后,你需要告诉 android 使用这个运行器:

    allprojects {
        ext {
            ....
            testInstrumentationRunner = "com...MyInstrumentationTestRunner"
        }
    }
    
    

    由于上述原因,应用程序上下文将是跨仪器测试的 TestMyApplication 实例。

    【讨论】:

    • 我最终扩展了我的 viewholder 类,它接收上下文对象作为参数,我在我的测试类中模拟了它(@mock lateinit var context context)。我会试试你的解决方案,谢谢
    【解决方案2】:

    这可以通过使用 Fake 来实现。假设您要模拟由 Application 类实现的接口。

    // main
    interface AppInitializer {
       val isUserLoggedIn: Boolean
    }
    
    class MyApplication : AppInitializer {
        override val isUserLoggedIn: Boolean
            get() = // ...
    }
    
    // test
    class FakeMyApplication : AppInitializer {
        override val isUserLoggedIn: Boolean
            get() = true
    
       // you need to override this
       override fun getApplicationContext(): Context {
            return this
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-11-02
      • 1970-01-01
      • 1970-01-01
      • 2014-06-24
      • 2011-07-01
      • 2011-05-11
      • 2011-06-04
      相关资源
      最近更新 更多