Android系统。 Mockito使用真实的对象而不是模拟

所以,我只是写简单的测试。 问题是测试运行器运行真正的“仓库”类代码,而不是模拟代码…你有什么想法,为什么我可以得到这个例外?

测试课

class SingInFacebookPresenterTest { @Mock private lateinit var view: SignInFacebookContract.View @Mock private lateinit var repository: Repository @Captor private lateinit var callback: ArgumentCaptor<RepositoryCallback.FacebookLoginImp> private lateinit var presenter: SingInFacebookPresenter private val serverToken = "token" @Before fun init() { MockitoAnnotations.initMocks(this) presenter = SingInFacebookPresenter(MockContext(), repository, view) } @Test fun facebook_login_success() { //Given val token = "token" val serverToken = "server token" presenter.loginViaFacebook(token) //When verify(repository).loginViaFacebook(token, callback.capture()) callback.value.onSuccess(serverToken) //Then verify(view).success(serverToken) } 

主持人

 class SingInFacebookPresenter(var context: Context, var repository: Repository, var view: SignInFacebookContract.View): SignInFacebookContract.Presenter { public override fun loginViaFacebook(token: String) { repository.loginViaFacebook(token, object : RepositoryCallback.FacebookLoginImp { override fun onSuccess(token: String) { view.success(token) } override fun onFailure() { view.onFailure() } }) } 

知识库

 open class Repository(context: Context) { init { ApiHelper(context) } private var facebookLoginPresenterCallback: RepositoryCallback.FacebookLoginImp? = null fun loginViaFacebook(token: String, facebookLoginPresenterCallback: RepositoryCallback.FacebookLoginImp?) { // this.facebookLoginPresenterCallback = facebookLoginPresenterCallback val signInResponse = ApiHelper.signInViaFacebook(token) // signInResponse.enqueue(signInFacebookCallback) signInResponse.enqueue(object : Callback<SignInResponse> { override fun onResponse(call: Call<SignInResponse>?, response: Response<SignInResponse>?) { if (response!!.isSuccessful) { val token = response.body()?.token ?: return facebookLoginPresenterCallback?.onSuccess(token) return } facebookLoginPresenterCallback?.onFailure() } override fun onFailure(call: Call<SignInResponse>?, t: Throwable?) { facebookLoginPresenterCallback?.onFailure() } }) } private val signInFacebookCallback = object : Callback<SignInResponse> { override fun onResponse(call: Call<SignInResponse>?, response: Response<SignInResponse>?) { if (response!!.isSuccessful) { val token = response.body()?.token ?: return facebookLoginPresenterCallback?.onSuccess(token) return } facebookLoginPresenterCallback?.onFailure() } override fun onFailure(call: Call<SignInResponse>?, t: Throwable?) { facebookLoginPresenterCallback?.onFailure() } } } 

例外:

 Exception in thread "OkHttp Dispatcher" java.lang.NoSuchMethodError: okhttp3.internal.Platform.log(Ljava/lang/String;)V at okhttp3.logging.HttpLoggingInterceptor$Logger$1.log(HttpLoggingInterceptor.java:109) at okhttp3.logging.HttpLoggingInterceptor.intercept(HttpLoggingInterceptor.java:157) at okhttp3.RealCall$ApplicationInterceptorChain.proceed(RealCall.java:190) at okhttp3.RealCall.getResponseWithInterceptorChain(RealCall.java:163) at okhttp3.RealCall.access$100(RealCall.java:30) at okhttp3.RealCall$AsyncCall.execute(RealCall.java:127) at okhttp3.internal.NamedRunnable.run(NamedRunnable.java:32) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) at java.lang.Thread.run(Thread.java:745) Exception in thread "OkHttp Dispatcher" java.lang.NoSuchMethodError: okhttp3.internal.Platform.log(Ljava/lang/String;)V at okhttp3.logging.HttpLoggingInterceptor$Logger$1.log(HttpLoggingInterceptor.java:109) at okhttp3.logging.HttpLoggingInterceptor.intercept(HttpLoggingInterceptor.java:157) at okhttp3.RealCall$ApplicationInterceptorChain.proceed(RealCall.java:190) at okhttp3.RealCall.getResponseWithInterceptorChain(RealCall.java:163) at okhttp3.RealCall.access$100(RealCall.java:30) at okhttp3.RealCall$AsyncCall.execute(RealCall.java:127) at okhttp3.internal.NamedRunnable.run(NamedRunnable.java:32) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) at java.lang.Thread.run(Thread.java:745) org.mockito.exceptions.base.MockitoException: No argument value was captured! You might have forgotten to use argument.capture() in verify()... ...or you used capture() in stubbing but stubbed method was not called. Be aware that it is recommended to use capture() only with verify() Examples of correct argument capturing: ArgumentCaptor<Person> argument = ArgumentCaptor.forClass(Person.class); verify(mock).doSomething(argument.capture()); assertEquals("John", argument.getValue().getName()); 

好的,这是一个好的。 这是我发现的:

测试代码不是问题,Mockito出于某种原因创建了Repository实例(?)实例。 或者至少没有拦截方法调用的地方?

无论如何,下面是一个完全简化的例子,它重现了org.mockito:mockito-core:2.7.11

 open class Greeter { fun hello() = "hello world" } class MockitoJavaExample { @Test fun test() { val greeter: Greeter = mock() println(greeter.hello()) // prints "hello world" which it shouldn't } } 

我对Mockito的内部知识不够熟悉,不知道这是怎么发生的,但是转而使用mockito-inline ,一种不同的mockito-inline方法解决了这个问题。 它还使您能够模拟Kotlin中的非open课程,无论如何您都可能需要这样做,以便您不必为了测试而打开课程进行扩展。 用这个方法,无论类是否打开,你都能正确的得到这个函数返回的null ,所以它不使用真正的实现。

您可以使用compile 'org.mockito:mockito-inline:2.7.11'而不是-core版本切换到compile 'org.mockito:mockito-inline:2.7.11'版本。