没有接口方法 isAsyncStarted() 错误 运行 wiremock android 在魅族设备上测试
No interface method isAsyncStarted() error running wiremock android tests on a Meizu device
我有一个 Android 应用程序可以执行网络请求。我在应用程序中使用 wiremock 进行仪器测试和改造。
请求被模拟成这样:
stubFor(
get(urlMatching("/hello/world"))
.willReturn(
aResponse()
.withStatus(HttpURLConnection.HTTP_OK)
.withHeader("Content-Type", "text/plain")
.withBody(expectedServerResponse)
)
)
改装界面:
interface HelloWorldService {
@GET("/hello/world")
fun getHelloWorld(): Call<ResponseBody>
}
执行请求的应用程序代码:
val helloWorldService =
Retrofit.Builder()
.baseUrl(intent.getStringExtra(EXTRA_BASE_URL))
.client((application as MyApplication).createRetrofitHttpClient())
.build()
.create(HelloWorldService::class.java)
helloWorldService.getHelloWorld().enqueue(object : Callback<ResponseBody> {
override fun onResponse(call: Call<ResponseBody>, response: Response<ResponseBody>) {
textView.text = if (response.isSuccessful) {
response.body()?.string()
} else {
response.message()
}
}
override fun onFailure(call: Call<ResponseBody>, t: Throwable) {
textView.text = t.message
}
})
当模拟响应的内容长度很大(超过 256 个字符),并且在魅族 Note 5 上测试 运行 时,wiremock 找到了响应并且看起来要发送 200
响应,正如我在 logcat 日志中看到的那样:
Matched response definition:
{
"status" : 200,
"body" : "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
"headers" : {
"Content-Type" : "text/plain"
}
}
Response:
HTTP/1.1 200
Content-Type: [text/plain]
Matched-Stub-Id: [a45b21c9-95f6-45fa-a7c3-acf473485fb6]
但是,该应用实际上收到了一个 500
错误代码,错误响应中包含以下消息:
No interface method isAsyncStarted()Z in class Ljavax/servlet/http/HttpServletRequest; or its super classes (declaration of 'javax.servlet.http.HttpServletRequest' appears in /system/framework/meizu2_jcifs.jar)
问题是wiremock和魅族都嵌入了javax.servlet
类,但是版本不同(不兼容)。一种解决方法是重新定位(更改包名称)wiremock 嵌入的 javax.servlet
类。
而不是像这样包含 wiremock:
androidTestImplementation "com.github.tomakehurst:wiremock-standalone:2.23.2"
使用 gradle shadow 插件并改用 shadowed jar:
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.github.jengelman.gradle.plugins:shadow:5.1.0'
}
}
apply plugin: com.github.jengelman.gradle.plugins.shadow.ShadowPlugin
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
android {
dependencies {
shadow "com.github.tomakehurst:wiremock-standalone:2.23.2"
androidTestImplementation files("$buildDir/libs/shadow.jar")
}
}
tasks.configureEach { theTask ->
def taskName = theTask.name.toString()
if (taskName =~ /generate.*Sources/) {
theTask.dependsOn tasks.named("shadowJar")
}
}
tasks.register("shadowJar", ShadowJar) {
baseName = 'shadow'
configurations = [project.configurations.shadow]
relocate ('javax.servlet', 'com.example.wiremockexample.javax.servlet'){}
}
这里有一个更详细地解释这个问题的完整示例项目:https://github.com/libon/WiremockMeizuError
项目上的 PR 实现了这个答案:https://github.com/libon/WiremockMeizuError/pull/1
我有一个 Android 应用程序可以执行网络请求。我在应用程序中使用 wiremock 进行仪器测试和改造。
请求被模拟成这样:
stubFor(
get(urlMatching("/hello/world"))
.willReturn(
aResponse()
.withStatus(HttpURLConnection.HTTP_OK)
.withHeader("Content-Type", "text/plain")
.withBody(expectedServerResponse)
)
)
改装界面:
interface HelloWorldService {
@GET("/hello/world")
fun getHelloWorld(): Call<ResponseBody>
}
执行请求的应用程序代码:
val helloWorldService =
Retrofit.Builder()
.baseUrl(intent.getStringExtra(EXTRA_BASE_URL))
.client((application as MyApplication).createRetrofitHttpClient())
.build()
.create(HelloWorldService::class.java)
helloWorldService.getHelloWorld().enqueue(object : Callback<ResponseBody> {
override fun onResponse(call: Call<ResponseBody>, response: Response<ResponseBody>) {
textView.text = if (response.isSuccessful) {
response.body()?.string()
} else {
response.message()
}
}
override fun onFailure(call: Call<ResponseBody>, t: Throwable) {
textView.text = t.message
}
})
当模拟响应的内容长度很大(超过 256 个字符),并且在魅族 Note 5 上测试 运行 时,wiremock 找到了响应并且看起来要发送 200
响应,正如我在 logcat 日志中看到的那样:
Matched response definition:
{
"status" : 200,
"body" : "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
"headers" : {
"Content-Type" : "text/plain"
}
}
Response:
HTTP/1.1 200
Content-Type: [text/plain]
Matched-Stub-Id: [a45b21c9-95f6-45fa-a7c3-acf473485fb6]
但是,该应用实际上收到了一个 500
错误代码,错误响应中包含以下消息:
No interface method isAsyncStarted()Z in class Ljavax/servlet/http/HttpServletRequest; or its super classes (declaration of 'javax.servlet.http.HttpServletRequest' appears in /system/framework/meizu2_jcifs.jar)
问题是wiremock和魅族都嵌入了javax.servlet
类,但是版本不同(不兼容)。一种解决方法是重新定位(更改包名称)wiremock 嵌入的 javax.servlet
类。
而不是像这样包含 wiremock:
androidTestImplementation "com.github.tomakehurst:wiremock-standalone:2.23.2"
使用 gradle shadow 插件并改用 shadowed jar:
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.github.jengelman.gradle.plugins:shadow:5.1.0'
}
}
apply plugin: com.github.jengelman.gradle.plugins.shadow.ShadowPlugin
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
android {
dependencies {
shadow "com.github.tomakehurst:wiremock-standalone:2.23.2"
androidTestImplementation files("$buildDir/libs/shadow.jar")
}
}
tasks.configureEach { theTask ->
def taskName = theTask.name.toString()
if (taskName =~ /generate.*Sources/) {
theTask.dependsOn tasks.named("shadowJar")
}
}
tasks.register("shadowJar", ShadowJar) {
baseName = 'shadow'
configurations = [project.configurations.shadow]
relocate ('javax.servlet', 'com.example.wiremockexample.javax.servlet'){}
}
这里有一个更详细地解释这个问题的完整示例项目:https://github.com/libon/WiremockMeizuError
项目上的 PR 实现了这个答案:https://github.com/libon/WiremockMeizuError/pull/1