Home » Android » android – Is there a way to write a unit test for a target API

android – Is there a way to write a unit test for a target API

Posted by: admin June 15, 2020 Leave a comment

Questions:

I am in the process of writing Android instrumented tests in an area were Robolectric custom shadows fall short.

Ideally, we want to write code that is flexible across all versions of the Android SDK however I am in an edge case situation where I need to write a individual unit test for a method that works only Marshmallow.

I also need to write a unit test that only works for Lollipop and under because of differences in operating system dependencies (i.e. java.lang.NoClassDefFoundError’s)

Is there anyway I can do this through Junit4-like annotations or something similar to what Robolectric does where it can ignore running the tests if the SDK is not a good fit?

I do not want to be writing code like this:

// MarshmallowWidgetTest.java
@Test
public void testPrintName()
{
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
    {
        // ...asserts...
    }
}

// LollipopWidgetTest.java
@Test
public void testPrintName()
{
    if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.LOLLIPOP)
    {
        // ...asserts...
    }
}
How to&Answers:

I’m not very familiar with unit testing or Robolectric, but because at time of writing unit tests by me there was no support for API 23 I used that config:

@RunWith(RobolectricGradleTestRunner.class)
@Config(constants = BuildConfig.class, sdk = 21) //this guy
public class MainActivityTest {

    MainActivity_ activity = Robolectric.setupActivity(MainActivity_.class);

}

So like you see there’s a annotation which you can use to your test classes.


EDIT:

Sorry that I focused only on Robolectric test framework, not main problem.

For annotating instrumentation tests for specific API I would use:

1. Class with @Before annotation

Create a class with @Before annotation, where it would check the API of tested devices. If wrong, the tests would fail in this method. Use fail(); method.

2. Use @SdkSuppress annotation

Indicates that a specific test or class requires a minimum API Level to execute.

Test(s) will be skipped when executed on android platforms less than specified level.

From: http://developer.android.com/reference/android/support/test/filters/SdkSuppress.html

So if you would set @SdkSuppress(minSdkVersion=23) it would run only on Android Marshmallow devices and if @@SdkSuppress(minSdkVersion=20) it would run only on higher 5.0 API devices.

Read also: http://www.vogella.com/tutorials/AndroidTesting/article.html

3. Create your own annotation like @SdkOnly

Maybe this article would be useful: http://help.testdroid.com/customer/portal/articles/1256803-using-annotations-in-android-instrumentation-tests

4. Create suites for your specific instrumentation tests

For this purpose you would use @RunWith() and Suites.SuiteClasses() annotations.

To organize the execution of your instrumented unit tests, you can
group a collection of test classes in a test suite class and run these
tests together. Test suites can be nested; your test suite can group
other test suites and run all their component test classes together.

A test suite is contained in a test package, similar to the main
application package. By convention, the test suite package name
usually ends with the .suite suffix (for example,
com.example.android.testing.mysample.suite).

To create a test suite for your unit tests, import the JUnit RunWith
and Suite classes. In your test suite, add the @RunWith(Suite.class)
and the @Suite.SuitClasses() annotations. In the @Suite.SuiteClasses()
annotation, list the individual test classes or test suites as
arguments.

The following example shows how you might implement a test suite
called UnitTestSuite that groups and runs the
CalculatorInstrumentationTest and CalculatorAddParameterizedTest test
classes together.

import com.example.android.testing.mysample.CalculatorAddParameterizedTest;
import com.example.android.testing.mysample.CalculatorInstrumentationTest;
import org.junit.runner.RunWith;
import org.junit.runners.Suite;

// Runs all unit tests.
@RunWith(Suite.class)
@Suite.SuiteClasses({CalculatorInstrumentationTest.class,
        CalculatorAddParameterizedTest.class})
public class UnitTestSuite {}

From: http://developer.android.com/training/testing/unit-testing/instrumented-unit-tests.html

5. Helpful resources

Hope it help