如何用 Robolectic 影响单身人士?
How to shadow singleton with Robolectic?
我有这样一个单身人士:
public class SingletonA{
private SingletonA instance = null;
private SingletonA(){
}
public static SingletonA getInstance(){
return instance ;
}
public static void init(){
System.loadLibrary("alib");
instance = new SingletonA();
}
......
other methods
}
如您所见,在使用它之前,我必须调用 SingletonA.init()。但是 Robolectric 无法加载 .so 文件。我想写一个ShadowSingletonA来代替它,但是不知道如何do.Because变量instance是私有的。任何人都可以帮忙吗?另外,class SingletonA来自第三方库,无法修改
这是我使其可测试的方法。
我们主要在应用程序中初始化第三方库 class。在某种程度上:
public class MyApplication {
public void onCreate() {
initSomeLibrary();
}
@VisibleForTests
@RestrictTo(RestrictTo.Scope.TESTS)
protected void initSomeLibrary() {
SomeLibrary.init(this);
}
}
Robolectric 将始终尝试加载清单中指定的应用程序,除非您已完成:
- Add
@Config
where you defined another app class name
- You put in test folder in the same package app class that has name Test
所以在这两种情况下,您都必须创建自定义应用程序。从历史上看,第一个选项更早可用,所以我坚持使用它。但是,它需要有关 Robolectric 的知识,所以我现在将我的测试应用程序 class 放到 @Config
部分(因此不再需要 Test):
public class TestMyApplication {
protected void initSomeLibrary() {
//nothing to do
}
}
处理依赖关系的另一种常用方法是将它们抽象化,使它们可以互换和测试。
所以假设你有一个很棒的库,下一个 API:
class LibraryName {
public static SomeSinglethon getInstance();
}
首先,创建抽象:
public class LibraryGenericPurpose {
public void doSomeThing(@NonNull String nameOfThing) {
LibraryName.getInstance().doSomething(new Event(nameOfThing));
}
}
首先请注意该方法不是静态的,因此您必须在刚刚从库中调用静态方法的所有地方添加额外的依赖项。有时候拥有这样的接口也很方便。
现在您更改使用它的地方:
class SomeClass {
public void someMethod() {
LibraryName.getInstance().doSomething(new Event(nameOfThing));
}
}
至:
class SomeClass {
@NonNull private LibraryGenericPurpose library;
public SomeClass(@NonNull LibraryGenericPurpose library) {
this.library = library;
}
public void someMethod() {
library.doSomeThing("Great!");
}
}
并且如果您无法像 Activity
或 Fragment
那样控制 class 生命周期,那么您必须学习如何在其中注入依赖项的新方法。
最后,在测试中,您根本不需要为 SomeClass
使用 Robolectric。通常这些 class 像 LibraryGenericPurpose
不能在 JVM 上测试(即使使用 Robolectric)并且很难或不可能在仪器测试中测试.
我有这样一个单身人士:
public class SingletonA{
private SingletonA instance = null;
private SingletonA(){
}
public static SingletonA getInstance(){
return instance ;
}
public static void init(){
System.loadLibrary("alib");
instance = new SingletonA();
}
......
other methods
}
如您所见,在使用它之前,我必须调用 SingletonA.init()。但是 Robolectric 无法加载 .so 文件。我想写一个ShadowSingletonA来代替它,但是不知道如何do.Because变量instance是私有的。任何人都可以帮忙吗?另外,class SingletonA来自第三方库,无法修改
这是我使其可测试的方法。 我们主要在应用程序中初始化第三方库 class。在某种程度上:
public class MyApplication {
public void onCreate() {
initSomeLibrary();
}
@VisibleForTests
@RestrictTo(RestrictTo.Scope.TESTS)
protected void initSomeLibrary() {
SomeLibrary.init(this);
}
}
Robolectric 将始终尝试加载清单中指定的应用程序,除非您已完成:
- Add
@Config
where you defined another app class name - You put in test folder in the same package app class that has name Test
所以在这两种情况下,您都必须创建自定义应用程序。从历史上看,第一个选项更早可用,所以我坚持使用它。但是,它需要有关 Robolectric 的知识,所以我现在将我的测试应用程序 class 放到 @Config
部分(因此不再需要 Test):
public class TestMyApplication {
protected void initSomeLibrary() {
//nothing to do
}
}
处理依赖关系的另一种常用方法是将它们抽象化,使它们可以互换和测试。
所以假设你有一个很棒的库,下一个 API:
class LibraryName {
public static SomeSinglethon getInstance();
}
首先,创建抽象:
public class LibraryGenericPurpose {
public void doSomeThing(@NonNull String nameOfThing) {
LibraryName.getInstance().doSomething(new Event(nameOfThing));
}
}
首先请注意该方法不是静态的,因此您必须在刚刚从库中调用静态方法的所有地方添加额外的依赖项。有时候拥有这样的接口也很方便。
现在您更改使用它的地方:
class SomeClass {
public void someMethod() {
LibraryName.getInstance().doSomething(new Event(nameOfThing));
}
}
至:
class SomeClass {
@NonNull private LibraryGenericPurpose library;
public SomeClass(@NonNull LibraryGenericPurpose library) {
this.library = library;
}
public void someMethod() {
library.doSomeThing("Great!");
}
}
并且如果您无法像 Activity
或 Fragment
那样控制 class 生命周期,那么您必须学习如何在其中注入依赖项的新方法。
最后,在测试中,您根本不需要为 SomeClass
使用 Robolectric。通常这些 class 像 LibraryGenericPurpose
不能在 JVM 上测试(即使使用 Robolectric)并且很难或不可能在仪器测试中测试.