你怎么投RuntimeEnvironment.application?
How do you cast RuntimeEnvironment.application?
运行Robolectric测试时,RuntimeEnvironment.application
的类型由你的配置决定。假设我将 RoboApplication.class 配置为我的测试应用程序,我可以将 RuntimeEnvironment.application 强制转换为我的类型。
RoboApplication app = (RoboApplication) RuntimeEnvironment.application;
app.doSomething();
但是,一旦我集成了 PowerMock,转换行就会失败
java.lang.ClassCastException: RoboApplication cannot be cast to RoboApplication
我该如何解决这个问题?
这是一个问题,因为 PowerMock 和 Robolectric 由于使用它们自己的 classloader.
而相互不兼容
即使名称相同,Class 对象实际上并不相同:Robolectric 和 PowerMock 都通过 custom [=40] 加载测试来工作=]装载机。这些 classloader 更改了有问题的 classes,允许您替换 static/final Android 系统 classes 和方法 [Robolectric] 或所有static/final classes [PowerMock]。这是 PowerMock 和 Robolectric 都依赖于拥有自己的 JUnit4 Runner 的部分原因:这样他们就可以从自己的修改 classloader 加载适当的 classes。
因此,无法将实例转换为彼此的 classes,即使它们具有相同的名称并且源自 来自同一来源文件:每个框架都可以更改 class 实现,因此它们不一定相互兼容。
您需要选择一个框架或另一个框架:使用 Robolectric shadows,可能直接使用 EasyMock 或 Mockito,或者使用 PowerMock 手动存根 Android 基础设施调用。
另请参阅:
- ClassCastException when casting to the same class
- cast across classloader?
我还需要应用程序参考才能启动 Dagger2 模块。经过几次尝试并得到相同的强制转换异常错误后,我按如下方式制作了我的应用程序
public class App extends Application {
private static AppComponent appComponent;
@Override
public void onCreate() {
super.onCreate();
if( appComponent==null ){
appComponent = DaggerAppComponent.builder().appModule(new AppModule(this)).build();
}
}
public static AppComponent getAppComponent() {
return appComponent;
}
public static void setAppComponent(AppComponent component){
appComponent = component;
}
}
在我的 Robolectric/PowerMock 测试仪中:
@Before
public void before() throws Exception {
App appMocked = PowerMockito.mock(App.class);
App.setAppComponent(DaggerAppComponent.builder().appModule(new AppModule(appMocked)).build());
....
}
然后我的activity就叫了App.getAppComponent().inject(this);
仅供参考,我尽量不嘲笑应用程序 class 并使用了 ((App)RuntimeEnvironment.application)
,但这没有用。我还尝试将其子化 class,并在 Robolectric 的应用程序配置中使用它,但最终遇到了转换问题。所以我希望这能有所帮助。
当然,setter 不应投入生产。但这是我认为这可行的唯一方法。
运行Robolectric测试时,RuntimeEnvironment.application
的类型由你的配置决定。假设我将 RoboApplication.class 配置为我的测试应用程序,我可以将 RuntimeEnvironment.application 强制转换为我的类型。
RoboApplication app = (RoboApplication) RuntimeEnvironment.application;
app.doSomething();
但是,一旦我集成了 PowerMock,转换行就会失败
java.lang.ClassCastException: RoboApplication cannot be cast to RoboApplication
我该如何解决这个问题?
这是一个问题,因为 PowerMock 和 Robolectric 由于使用它们自己的 classloader.
而相互不兼容即使名称相同,Class 对象实际上并不相同:Robolectric 和 PowerMock 都通过 custom [=40] 加载测试来工作=]装载机。这些 classloader 更改了有问题的 classes,允许您替换 static/final Android 系统 classes 和方法 [Robolectric] 或所有static/final classes [PowerMock]。这是 PowerMock 和 Robolectric 都依赖于拥有自己的 JUnit4 Runner 的部分原因:这样他们就可以从自己的修改 classloader 加载适当的 classes。
因此,无法将实例转换为彼此的 classes,即使它们具有相同的名称并且源自 来自同一来源文件:每个框架都可以更改 class 实现,因此它们不一定相互兼容。
您需要选择一个框架或另一个框架:使用 Robolectric shadows,可能直接使用 EasyMock 或 Mockito,或者使用 PowerMock 手动存根 Android 基础设施调用。
另请参阅:
- ClassCastException when casting to the same class
- cast across classloader?
我还需要应用程序参考才能启动 Dagger2 模块。经过几次尝试并得到相同的强制转换异常错误后,我按如下方式制作了我的应用程序
public class App extends Application {
private static AppComponent appComponent;
@Override
public void onCreate() {
super.onCreate();
if( appComponent==null ){
appComponent = DaggerAppComponent.builder().appModule(new AppModule(this)).build();
}
}
public static AppComponent getAppComponent() {
return appComponent;
}
public static void setAppComponent(AppComponent component){
appComponent = component;
}
}
在我的 Robolectric/PowerMock 测试仪中:
@Before
public void before() throws Exception {
App appMocked = PowerMockito.mock(App.class);
App.setAppComponent(DaggerAppComponent.builder().appModule(new AppModule(appMocked)).build());
....
}
然后我的activity就叫了App.getAppComponent().inject(this);
仅供参考,我尽量不嘲笑应用程序 class 并使用了 ((App)RuntimeEnvironment.application)
,但这没有用。我还尝试将其子化 class,并在 Robolectric 的应用程序配置中使用它,但最终遇到了转换问题。所以我希望这能有所帮助。
当然,setter 不应投入生产。但这是我认为这可行的唯一方法。