Obeying the rules ?

Challenge accepted

Rules are there to be broken? nope!! Extend them:) In one of my current Assignments/Projects I’m learning/I’ve learned quite a lot about the world of the mobile web and how to test untestable or uncharted areas of the code.

@sirTestsAlot once said :
Go!! where no Runner has gone before.

test it and it shall pass!!

boldly test code where rules don’t seem to apply, test the darkest matter of all — Code within WebView :p

One important part of the testing process is exploring/understanding how JS code runs in Webview and how we can create reliable tests verifying our code base SDK module works properly.

When testing code we usually use Junit, Espresso, Mockito and Android Runner. Sometimes, we want to write code to inspect a test before it runs, modify whether and how to run the test, and inspect and modify test results so we use Rules.

JUnit rules

Rules Overview

JUnit rule mechanism has 3 main parts:

  • Statements - runs the tests.
  • Rules - choose which statement to use to run the tests.
  • @Rule annotations - tell JUnit what to apply on our test class/method.

Flow

In order to execute we can say JUnit roughly follows this Flow :

  • Create a default statement to run the test.
  • Find all of test class’s rules by looking for public member fields annotated with @Rule.
  • Call each rule’s apply() method, telling which test class and method are to be run, and what statement JUnit has gathered so far. apply() decides how to run the test, selects or creates the appropriate statement to run the test, and returns that statement to JUnit. JUNit then passes this statement to the next rule’s apply() method, and so on.
  • Run the test by calling the evaluate() method of the statement returned by the last rule.

Applying Rules

To use a rule in our test class, we declare a public member field, initialize the field with an instance of our rule class, and annotate the field with @Rule:

public class RepeatRuleTest {
    @Rule
    public RepeatRule repeatRule = new RepeatRule();

    @Test
    @RepeatRule.Repeat(NUM_ITERATIONS)
    public void RepeatRest() { ... }

    ...
}

In this simple class we use our custom RepeatRule Rule class
and issue the test to run multiple times (NUM_ITERATIONS)

Parameterized tests

In some of our tests we might want to run the same test but with different parameters, allowing us to change specific variable value in multiple runs and test a set of configurations in a suite of tests.

Our Runner will change as we will use Parameterized Runner.

@RunWith(Parameterized.class)
public class SampleParamsTest {

@Parameterized.Parameters public static Collection<Object[]> data() {

        return Arrays.asList(new Object[][]{
                {MB_1, TIMEOUT_MB_1},
                {MB_10, TIMEOUT_MB_10},
                {MB_20, TIMEOUT_MB_20},
                {MB_30, TIMEOUT_MB_30},
                {MB_40, TIMEOUT_MB_40},
                {MB_50, TIMEOUT_MB_50},
                {MB_100, TIMEOUT_MB_100}
        });
    }

    @Parameterized.Parameter(0)
    public static int size;

    @Parameterized.Parameter(1)
    public static long threshold;

In this example we use the @RunWith annotation to indicate we want to use an Parameterized Runner. The @Parameterized.Parameters annotaion is used to declare the parameters we want to use during the test.

Instead of using a constructor we use the @Parameter annotaion. Parameter(0) is the same as Parameter as the default is 0. We can iterate the values we need from our Collection and so we do the in this example.

Another thing to note, When our test relies on a single parameter we don't need to wrap it with an array. We use Iterable or an array of objects.

@Parameters
public static Iterable<? extends Object> data() {
    return Arrays.asList(MB_1, MB_10, MB_20, MB_30, MB_40);
}

or

@Parameters
public static Object[] data() {
    return new Object[] { TIMEOUT_MB_1, TIMEOUT_MB_10, TIMEOUT_MB_20, TIMEOUT_MB_30 };
}

All sample code is available in this gist

Of course, The world of testing has a lot more packed within.

Till next time...