11

I want to back up my application's database before replacing it with the test fixture. I'm forced to use Junit3 because of Android limitations, and I want to implement the equivalent behavior of @BeforeClass an @AfterClass.

UPDATE: There is now a tool (Junit4Android) to get support for Junit4 on Android. It's a bit of a kludge but should work.

To achieve the @BeforeClass equivalent, I had been using a static variable and initializing it during the first run like this, but I need to be able to restore the database after running all the tests. I can't think of a way of detecting when the last test has run (since I believe there is no guarantee on the order of test execution.)

public class MyTest extends ActivityInstrumentationTestCase2<MainActivity> {
    private static boolean firstRun = true;

    @Override
    protected void setUp() {
        if(firstRun) {
            firstRun = false;
            setUpDatabaseFixture();
        }
    }
    ...
}
Jeff Axelrod
  • 27,676
  • 31
  • 147
  • 246
  • But in your case tests will be depending on each other and would be expecting the database in some particular state implying they are not true unit tests. You should you a mock database. – Diego Torres Milano Aug 26 '11 at 21:54
  • 1
    These are acceptance tests, and most certainly are not unit tests. These are fully integrated on the platform, driven by an Android tool called Robotium. – Jeff Axelrod Aug 26 '11 at 22:10
  • See also http://stackoverflow.com/questions/3023091/does-junit-3-have-something-analogous-to-beforeclass – Vadzim Aug 29 '13 at 12:34

4 Answers4

8

From the junit website:

Wrapped the setUp and tearDown method in the suite.This is for the case if you want to run a single YourTestClass testcase.

public static Test suite() {
    return new TestSetup(new TestSuite(YourTestClass.class)) {

        protected void setUp() throws Exception {
            System.out.println(" Global setUp ");
        }
        protected void tearDown() throws Exception {
            System.out.println(" Global tearDown ");
        }
    };
}

If you would like to run only one setUp and tearDown for all the testcase, make a suite and add testClass to it and pass the suite object in TestSetup constructor.But I think there is not much usage for this,and in a way it is violating JUnit philosophy.

nicholas.hauschild
  • 42,483
  • 9
  • 127
  • 120
  • Note that TestSetup seems to be in `junit.extensions.TestSetup` – Peter Ajtai Nov 22 '11 at 17:38
  • 3
    @PeterAjtai and Nicholas, though this would work on other platforms, Android [doesn't include support](http://stackoverflow.com/q/10691737/403455) for `junit.extensions.TestSetup`. – Jeff Axelrod Jun 26 '12 at 20:16
  • are you running this code on ANdroid? Could you please share the full code with me? I'm struggling to implement the Global setUp/tearDown.. – Felipe Mosso Jul 23 '14 at 20:08
1

Recently, I was looking for a similar solution too. Fortunately, in my case after the JVM exits after the last test is run. So I was able to achieve this by adding a JVM shutdown hook.

// Restore database after running all tests
Runtime.getRuntime().addShutdownHook(new Thread() {
    public void run() {
        restoreDatabase();
    }
});

hope this helps.

Drupad Panchal
  • 383
  • 3
  • 10
0

I would suggest avoiding these kind of dependencies where you need to know the order in which tests are run. If all you need is to restore a real database that was replaced by setUpDatabaseFixture() probably you solution comes from the use of a RenamingDelegatingContext. Anyway, if you can't avoid knowing when the last test was run, you can use something like this:

...

private static final int NUMBER_OF_TESTS = 5; // count your tests here
private static int sTestsRun = 0;

...

protected void tearDown() throws Exception {
    super.tearDown();
    sTestsRun += countTestCases();

    if ( sTestsRun >= NUMBER_OF_TESTS ) {
        android.util.Log.d("tearDow", "*** Last test run ***");
    }
}
Jeff Axelrod
  • 27,676
  • 31
  • 147
  • 246
Diego Torres Milano
  • 65,697
  • 9
  • 111
  • 134
0

Isn't this (dealing elegantly with data, so you don't have to worry about restoring it) what testing with mock objects are for? Android supports mocking.

I ask as a question, since I've never mocked Android.


In my experiences, and from this blog post, when the Android tests are made into a suite and run by the InstrumentationTestRunner - ActivityInstrumentationTestCase2 is an extension of ActivityTestCase which is an extendsion of InstrumentationTestCase - they are ordered alphabetically using android.test.suitebuilder.TestGrouping.SORT_BY_FULLY_QUALIFIED_NAME, so you can just restore you DB with a method that is the lowes in the alphabet out of your test names, like:

// underscore is low in the alphabet
public void test___________Restore() { 
    ... 
}

Note:

You have to pay attention to inherited tests, since they will not run in this order. The solution is to override all inherited test and simply call super() from the override. This will once again have everything execute alphabetically.

Example:

// Reusable class w only one time setup and finish. 
// Abstract so it is not run by itself.
public abstract class Parent extends InstrumentationTestCase {
    @LargeTest
    public void test_001_Setup() { ... }

    @LargeTest
    public void test_____Finish() { ... }
}

/*-----------------------------------------------------------------------------*/

// These will run in order shown due to naming.
// Inherited tests would not run in order shown w/o the use of overrides & supers
public class Child extends Parent {
    @LargeTest
    public void test_001_Setup() { super.test_001_Setup(); }

    @SmallTest
    public void test_002_MainViewIsVisible() { ... }

    ...

    @LargeTest
    public void test_____Finish() { super.test_____Finish(); }
}
Community
  • 1
  • 1
Peter Ajtai
  • 56,972
  • 13
  • 121
  • 140
  • Thanks, but this is for acceptance testing, not unit tests. I already use PowerMock + Mockito to create mocks for running fast unit tests on the host PC. – Jeff Axelrod Nov 22 '11 at 22:03
  • @glen - Oh ok, that makes sense. I think Android tests are run alphabetically, so you can just create a testZZZZZ() that restores everything. From http://blogprogramistyandroid.blogspot.com/2011/02/randomizing-order-of-tests.html android.test.suitebuilder.TestGrouping.SORT_BY_FULLY_QUALIFIED_NAME – Peter Ajtai Nov 22 '11 at 22:31