Qian Sijianhao Qian Sijianhao - 5 months ago 28
Android Question

How to shadow singleton with Robolectic?

I have such a singleton:

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
}


As you can see, before use it , I have to call SingletonA.init().But Robolectric can not load .so file. I want to write a ShadowSingletonA to replace it, but don't know how to do.Because variable instance is private. Can any one help? Besides, class SingletonA is from some third part library so I can not do any modification to it.

Answer Source

Another common way to deal with you dependencies abstract them to make them interchangeable and testable.

So assume you have great library with next API:

class LibraryName {
    public static SomeSinglethon getInstance();
}

First, create the abstraction:

public class LibraryGenericPurpose {
   public void doSomeThing(@NonNull String nameOfThing) {
      LibraryName.getInstance().doSomething(new Event(nameOfThing));
   }
}

First note that the method is not static, so you have to add an extra dependency in all places where you were just calling static methods from the library. Sometimes it is handy also to have the interface for such thing.

And now you change a place where you use it from:

class SomeClass {
    public void someMethod() {
        LibraryName.getInstance().doSomething(new Event(nameOfThing));
    }
}

to:

class SomeClass {
    @NonNull private LibraryGenericPurpose library;

    public SomeClass(@NonNull LibraryGenericPurpose library) {
        this.library = library;
    }

    public void someMethod() {
        library.somMethod();
    }
}

And if you don't have control over the class life cycle as Activity or Fragment then you have to learn new ways how to inject dependencies there.

Finally, in the tests, you don't need to use Robolectric for SomeClass at all. And quite often these classes like LibraryGenericPurpose are not testable on JVM (even with Robolectric) and quite hard or impossible to test in instrumental tests.