所以,我只是写简单的测试。 问题是测试运行器运行真正的存储库'类代码而不是模拟代码...... 你知道为什么我会对此有例外吗?
测试课
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());
答案 0 :(得分:2)
好的,这是一个很好的。这是我发现的:
测试代码不是问题,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
,一种不同的模拟方法解决了这个问题。它还使您能够在Kotlin中模拟非open
类,无论如何您都可能想要这样,以便您不必打开扩展类来测试它们。使用此方法,无论该类是否已打开,您都可以正确地获取该函数返回的null
,因此它不会使用实际的实现。
您可以使用compile 'org.mockito:mockito-inline:2.7.11'
代替-core
版本切换到Mockito的内联版本。