Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Restarting application on android test

I'm making a library which will process information according to the user default settings and will save it on SharedPreferences, which can be modified by the developer on their application before initializing my library.

The SDK should only be initialized once per application instance, otherwised will trigger a RuntimeError. So on the application side on Application class should be something like this:

public class SampleApplication extends Application {
    @Override
    public void onCreate() {
       super.onCreate();

       //Here I can do something that will change the default configs

       //Here I initialize the SDK singleton method
       Sdk.initialize();
    }
}

The sdk abstract implementation:

public class Sdk {

    private static SampleApplication sInstance;

    private void Sdk(){
    }

    public static SampleApplication getInstance() throws RuntimeException {
        if (sInstance == null) {
            throw new RuntimeException();
        }
        return sInstance;
    }

    public static void initialize() {
        if (sInstance == null) {
            sInstance = new Sdk();
            //save some information according to what is on the default configurations
        } else {
            throw new RuntimeException("Method was already initialized");
        }
    }
}

The problem comes when I want to test several scenarios to call this method (which can only be called once per application instance).

So I created an Android Test which extends the ApplicationTest

ApplicationTest:

  public class ApplicationTest extends ApplicationTestCase<SampleApplication> {
        public ApplicationTest() {
            super(SampleApplication.class);
        }
    }

Android Test Sample:

public class SampleTest extends ApplicationTest {

    @Override
    protected void setUp() throws Exception {
// Here I restart the user preferences although I need to restart the application
//        terminateApplication();
//        createApplication();
        super.setUp();
    }

    @Override
    protected void tearDown() throws Exception {
        super.tearDown();
    }

    public void testDefaultSettings() {
        // Here is where I want to restart application input
        // some values on the user preferences settings in order 
        // to test the output on sharedpreferences by the initialized method  
    }
}

I tried to terminate and create application again but with no success. My question is it is possible to restart the application of a Android test? Am I doing something wrong here?

like image 283
iGoDa Avatar asked Dec 18 '15 18:12

iGoDa


People also ask

How can I test my Android app?

Using Studio, you can point and click in the app source code to create and run tests for specific classes or methods, use drop-down menus to configure multiple test devices, and interact with the Text Matrix tool window to visualize test results.

What is runtime test in Android?

The suite is built using the Android testing framework. The runner is implemented as a single instrumentation test that executes the test package and parses the result log. The logs are taken directly from the device (logcat).


1 Answers

I believe, the problem you really struggling with is an InstrumentationTestRunner's issue: How to prevent ActivityUnitTestCase from calling Application.onCreate? (and, apparently, there's no obvious fix for it)

I.e. TestRunner is going to call onCreate() during its initialization anyway, so once you call createApplication(), your Sdk is already initialized.

Regarding the question itself - I believe, the only option is to rethink the architecture of the Sdk class (or adding some "reset" function, etc.)

public class TestApplication extends Application {

    @Override
    public void onCreate() {
        super.onCreate();
        // Sdk.terminate(); - If you specify TestApplication as an 
        //                    application class in AndroidManifest, 
        //                    you'll have to uncomment this(due to issue with test runner)
        Sdk.initialize();
    }

    @Override
    public void onTerminate() {
        super.onTerminate();
        Sdk.terminate();
    }
}

Sdk class

public class Sdk {

    private static Sdk sInstance;
    private void Sdk(){
    }

    public static Sdk getInstance() throws RuntimeException {
        if (sInstance == null) {
            throw new RuntimeException();
        }
        return sInstance;
    }

    public static void terminate() {
        sInstance = null;
    }

    public static void initialize() {
        if (sInstance == null) {
            sInstance = new Sdk();
            //save some information according to what is on the default configurations
        } else {
            throw new RuntimeException("Method was already initialized");
        }
    }
}

Tests:

public class MyApplicationTest extends ApplicationTestCase<TestApplication> {

    public MyApplicationTest() {
        super(TestApplication.class);
    }

    public void testMultiplicationTests() {
        createApplication();

        int answer = 42;
        assertEquals(42, answer);

        terminateApplication();
    }


    public void testDefaultSettings() {
        createApplication();

        assertNotNull(Sdk.getInstance());

        terminateApplication();
    }
}

NB! You can make it a bit less paiful, if you apply special AndroidManifest for androidTest. Then, you won't struggle with issue of TestRunner, when it calls onCreate() by itself before tests start.

I hope, it helps

like image 61
Konstantin Loginov Avatar answered Oct 26 '22 19:10

Konstantin Loginov