在单位测试期间,在ViewModel中订阅了NullPoInterException,以订阅可观察到



我正在尝试在我的ViewModel类上运行单元测试,但是当我运行测试时,我将获得NullPoInterException。getDatamanager()。getAuthToken()方法使用Raturofit调用API并返回字符串响应。有什么方法可以测试" startLogin()"方法?这是代码。

loginViewModeltest.kt

@RunWith(JUnit4::class)
class LoginViewModelTest {
    @Rule
    @JvmField
    var instantTaskExecutorRule =  InstantTaskExecutorRule()
    companion object {
        @ClassRule
        @JvmField
        val schedulers = RxSchedulerRule()
    }
    private val application = mock(Application::class.java)
    private val dataManager = mock(DataManager::class.java)
    private val serviceConnector = mock(ServiceConnector::class.java)
    private val requestInterceptor = mock(RequestInterceptor::class.java)
    private lateinit var compositeDisposable: CompositeDisposable
    private lateinit var loginViewModel: LoginViewModel
    @Before
    fun setup() {
        MockitoAnnotations.initMocks(this)
        compositeDisposable = CompositeDisposable()
        loginViewModel = LoginViewModel(application, dataManager, serviceConnector, compositeDisposable, requestInterceptor)
    }
    @Test
    fun testLoginWithValidQR(){
        val map = QueryMapBuilder.getAuthTokenHeaders()
        val body = TokenReqBody()
        val success = TokenResSuccess()
        `when`(dataManager.getAuthToken(map, body)).thenReturn(Observable.just(success))
        assertNotNull(dataManager.getAuthToken(map, body))
        // got error here
        loginViewModel.startLogin()
    }
}

loginviewmodel.java

public class LoginViewModel extends BaseViewModel {
    private RequestInterceptor mRequestInterceptor;
    private SingleLiveEvent<LoginViewDataEvents> loginViewDataSingleLiveEvent;
    @Inject
    public LoginViewModel(Application application, DataManager dataManager, ServiceConnector serviceConnector, CompositeDisposable compositeDisposable, RequestInterceptor requestInterceptor) {
        super(application, dataManager, serviceConnector, compositeDisposable);
        mRequestInterceptor = requestInterceptor;
        loginViewDataSingleLiveEvent = new SingleLiveEvent<>();
    }
    public void startLogin() {
        Map<String, String> map = QueryMapBuilder.getAuthTokenHeaders();
        TokenReqBody body = QueryMapBuilder.getAuthTokenBody(AppConfig.getConfig());
        getCompositeDisposable().add(getDataManager().getAuthToken(map, body)
                .subscribeOn(Schedulers.io()) //getting error here
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe()
            );
    }
}

错误日志

java.lang.NullPointerException
at com.example.doc.ui.login.LoginViewModel.startLogin(LoginViewModel.java:102)
at com.example.doc.login.LoginViewModelTest.testLoginWithValidQR(LoginViewModelTest.kt:86)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
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 org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
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 com.example.doc.RxSchedulerRule$apply$1.evaluate(RxSchedulerRule.kt:44)

startLogin函数中获取null的原因是因为java通过参考传递了非主要变量,这意味着它传递了内存地址,而不是值本身。dataManager.getAuthToken(map, body)的首次使用传递是因为您使用的是定义'when'语句的相同对象mapbody(它们具有相同的内存地址)。第二次(在函数内部),您使用的是具有新内存地址的全新对象,因此'when'语句不会触发。解决方案是将'when'语句更改为:

`when`(dataManager.getAuthToken(any(), any())).thenReturn(Observable.just(success))

这意味着语句将用>传递给该功能的任何触发。

问题是,在单位测试中,您正在为datamanager创建一个新对象

private val dataManager = mock(DataManager::class.java) 

并使用它来调用dataManager.getAuthToken(map, body);

但是,在loginviewModel内部的实际实现中,您使用以下行,

getDataManager().getAuthToken(map, body)

这里getDatamanager()为null。因此,您需要添加以下行使其工作,

when(getDataManager()).thenReturn(dataManager);

相关内容

  • 没有找到相关文章