将 MockWebServer 与 Robolectric 一起使用
Using MockWebServer with Robolectric
我正在尝试使用 MockWebServer 和 Robolectric 对一些 API 调用进行单元测试。
我的测试 class 注释为:
@RunWith(RobolectricGradleTestRunner.class)
@Config(constants = BuildConfig.class, sdk = 23)
然而,在尝试构建 Retrofit 实例时,出现以下异常:
java.lang.NullPointerException
at android.os.Handler.__constructor__(Handler.java:229)
at android.os.Handler.<init>(Handler.java)
at retrofit2.Platform$Android$MainThreadExecutor.<init>(Platform.java:105)
at retrofit2.Platform$Android.defaultCallbackExecutor(Platform.java:97)
at retrofit2.Retrofit$Builder.build(Retrofit.java:556)
我用来构建改造实例的代码:
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(mMockServer.url(""))
.addConverterFactory(GsonConverterFactory.create())
.build();
调用.build()
.
时返回上述异常
我该如何解决这个问题?
你可以用 sdk=21 试试。我相信对 sdk=23 的支持仅从 3.1-SNAPSHOT 添加,而不是发布版本。
编辑:我错了 支持是从 3.1 版添加的,因为我可以成功 运行 测试
@RunWith(RobolectricGradleTestRunner.class)
@Config(constants = BuildConfig.class, sdk = 23)
public class ExampleUnitTest {
private MockWebServer mMockServer = new MockWebServer();
@Test
public void build_retrofit() throws Exception {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(mMockServer.url(""))
.addConverterFactory(GsonConverterFactory.create())
.build();
}
}
我的gradle.build
testCompile 'junit:junit:4.12'
testCompile "org.robolectric:robolectric:3.1"
testCompile 'com.squareup.okhttp3:mockwebserver:3.3.0'
compile 'com.squareup.retrofit2:retrofit:2.1.0'
compile 'com.squareup.retrofit2:converter-gson:2.1.0'
您使用的是哪个库版本?
我遇到了同样的问题。有一个关于根本原因 here but while that is ongoing, I settled for using Robolectric 3.0 and the solution outlined by dave-r12 here 的错误,它是创建我在下面包含的模拟。
@RunWith(RobolectricGradleTestRunner.class)
@Config(shadows = CreateOkHttpClientTest.MyNetworkSecurityPolicy.class)
public class CreateOkHttpClientTest {
@Test
...
@Implements(NetworkSecurityPolicy.class)
public static class MyNetworkSecurityPolicy {
@Implementation
public static NetworkSecurityPolicy getInstance() {
try {
Class<?> shadow = MyNetworkSecurityPolicy.class.forName("android.security.NetworkSecurityPolicy");
return (NetworkSecurityPolicy) shadow.newInstance();
} catch (Exception e) {
throw new AssertionError();
}
}
@Implementation
public boolean isCleartextTrafficPermitted() {
return true;
}
}
}
另一种似乎可行的解决方案是在设置 Retrofit 时仅提供一个虚拟执行程序
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://www.example.com/")
.client(client)
.callbackExecutor(new Executor() {
@Override
public void execute(Runnable command) {
//doesn't matter since tests are synchronous
}
})
.addConverterFactory(ScalarsConverterFactory.create())
.build();
可能最终需要在 Retrofit 方面进行更正,以某种方式检测当前平台是否是 Robolectric 和 return 虚拟执行程序或其他东西。
如果您卡在 Robolectric 3 或以下并且您的目标是 API 25,则正确的解决方案与公认的解决方案几乎相同。
@Implements(NetworkSecurityPolicy.class)
public class NetworkSecurityPolicyShadow {
@Implementation
public static NetworkSecurityPolicy getInstance() {
try {
Class<?> shadow = Class.forName("android.security.NetworkSecurityPolicy");
return (NetworkSecurityPolicy) shadow.newInstance();
} catch (Exception e) {
throw new AssertionError();
}
}
@Implementation
public boolean isCleartextTrafficPermitted(String host) {
return true;
}
}
唯一的区别在于 isCleartextTrafficPermitted(String host)
,因为 OkHttp 将尝试使用 host
参数调用此方法。
我正在尝试使用 MockWebServer 和 Robolectric 对一些 API 调用进行单元测试。
我的测试 class 注释为:
@RunWith(RobolectricGradleTestRunner.class)
@Config(constants = BuildConfig.class, sdk = 23)
然而,在尝试构建 Retrofit 实例时,出现以下异常:
java.lang.NullPointerException
at android.os.Handler.__constructor__(Handler.java:229)
at android.os.Handler.<init>(Handler.java)
at retrofit2.Platform$Android$MainThreadExecutor.<init>(Platform.java:105)
at retrofit2.Platform$Android.defaultCallbackExecutor(Platform.java:97)
at retrofit2.Retrofit$Builder.build(Retrofit.java:556)
我用来构建改造实例的代码:
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(mMockServer.url(""))
.addConverterFactory(GsonConverterFactory.create())
.build();
调用.build()
.
我该如何解决这个问题?
你可以用 sdk=21 试试。我相信对 sdk=23 的支持仅从 3.1-SNAPSHOT 添加,而不是发布版本。
编辑:我错了 支持是从 3.1 版添加的,因为我可以成功 运行 测试
@RunWith(RobolectricGradleTestRunner.class)
@Config(constants = BuildConfig.class, sdk = 23)
public class ExampleUnitTest {
private MockWebServer mMockServer = new MockWebServer();
@Test
public void build_retrofit() throws Exception {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(mMockServer.url(""))
.addConverterFactory(GsonConverterFactory.create())
.build();
}
}
我的gradle.build
testCompile 'junit:junit:4.12'
testCompile "org.robolectric:robolectric:3.1"
testCompile 'com.squareup.okhttp3:mockwebserver:3.3.0'
compile 'com.squareup.retrofit2:retrofit:2.1.0'
compile 'com.squareup.retrofit2:converter-gson:2.1.0'
您使用的是哪个库版本?
我遇到了同样的问题。有一个关于根本原因 here but while that is ongoing, I settled for using Robolectric 3.0 and the solution outlined by dave-r12 here 的错误,它是创建我在下面包含的模拟。
@RunWith(RobolectricGradleTestRunner.class)
@Config(shadows = CreateOkHttpClientTest.MyNetworkSecurityPolicy.class)
public class CreateOkHttpClientTest {
@Test
...
@Implements(NetworkSecurityPolicy.class)
public static class MyNetworkSecurityPolicy {
@Implementation
public static NetworkSecurityPolicy getInstance() {
try {
Class<?> shadow = MyNetworkSecurityPolicy.class.forName("android.security.NetworkSecurityPolicy");
return (NetworkSecurityPolicy) shadow.newInstance();
} catch (Exception e) {
throw new AssertionError();
}
}
@Implementation
public boolean isCleartextTrafficPermitted() {
return true;
}
}
}
另一种似乎可行的解决方案是在设置 Retrofit 时仅提供一个虚拟执行程序
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://www.example.com/")
.client(client)
.callbackExecutor(new Executor() {
@Override
public void execute(Runnable command) {
//doesn't matter since tests are synchronous
}
})
.addConverterFactory(ScalarsConverterFactory.create())
.build();
可能最终需要在 Retrofit 方面进行更正,以某种方式检测当前平台是否是 Robolectric 和 return 虚拟执行程序或其他东西。
如果您卡在 Robolectric 3 或以下并且您的目标是 API 25,则正确的解决方案与公认的解决方案几乎相同。
@Implements(NetworkSecurityPolicy.class)
public class NetworkSecurityPolicyShadow {
@Implementation
public static NetworkSecurityPolicy getInstance() {
try {
Class<?> shadow = Class.forName("android.security.NetworkSecurityPolicy");
return (NetworkSecurityPolicy) shadow.newInstance();
} catch (Exception e) {
throw new AssertionError();
}
}
@Implementation
public boolean isCleartextTrafficPermitted(String host) {
return true;
}
}
唯一的区别在于 isCleartextTrafficPermitted(String host)
,因为 OkHttp 将尝试使用 host
参数调用此方法。