Robolectric - Unit Testing Android Applications

23:54 Posted by Unknown 3 comments

What is Unit Testing?

Unit Testing is the testing of the individual units of source code. Now, what is a unit in source code? It is the smallest piece of code that is testable in the entire source code. The test cases we write to test these small chunks of code are called Unit Test Cases.

What is Unit Testing?
What is Unit Testing?
Why should we write Unit Test Cases?

There are several reasons for why we should write them. Few of them are:
  1. You can change or modify your code with more confidence. It means that you can be more confident that your change or implementation does not break any other feature or code.
  2. To facilitate unit tests, you have to write your code in a modular way. If your code is too complicated or if your class becomes too complex, you cannot (or it is very difficult) write unit test cases. So, it actually forces you to write modular code. This makes the maintenance of your code easier.
  3. It helps you develop faster. Let me explain. Say, you have to perform some three to four clicks to get to the point of your code in your actual testing on the device. In order to test the logic you write, you have to build, deploy and do all the above steps to get to that place. A mistake in code, go back and do all of it again! Its a pain and time consuming. But with Unit testing, the testing of your logic happens at the time of running your unit test cases only. Thus, it takes a little time to figure out bugs and test your logic.
Lets consider an example:
    class MyClass {
        int add(int a, int b) {
            return a + b;   // your business logic
        }
    }
    
    class MyClassTest {
        @Test
        void shouldAddBothNumbers() {
            MyClass myClass = new MyClass();
            int sum = myClass.add(1, 2);                    
            assertTrue(sum == 3);   // testing the logic
        }
    }

Here, your testing framework makes the call to your add() method and verifies its result. Instead of you deploying this onto the execution of environment and getting to the point of manually executing it, your test cases does the testing for you. Simple, sweet and straight forward!

What is Robolectric?

In the above example, it is a simple test case, which doesnt involve any of the native APIs of an execution environment.

Coming to Android, you typically use a lot of native APIs in your application code. In order to test this code, you need a testing environment which understands these APIs. It should then test and tell you if it does what it should do.

Robolectric is a Unit test framework which exactly does the same. It understands these and tests them during compilation itself. So, you need not actually run your code on a device to test your logic. This makes your development faster and more efficient.

Lets look at an example
    // Main Activity
    public class MyActivity extends Activity {

        private Button mButton;

        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.main);

            mButton = (Button) findViewById(R.id.button);
            mButton.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    Toast.makeText(
                            getBaseContext(), "button clicked",
                            Toast.LENGTH_SHORT).show();
                }
            });
        }
    }

    // Unit test case class
    @RunWith(RobolectricTestRunner.class)
    public class MyActivityTest {

        private MyActivity mMyActivity;

        @Before
        public void setup() {
            mMyActivity = Robolectric.buildActivity(MyActivity.class)
                          .create().get();
        }

        @Test
        public void toastShouldBeDisplayedOnButtonClick() {
            Button button = (Button) mMyActivity.findViewById(R.id.button);
            button.performClick(); // Perform the click..!!

            String toast = ShadowToast.getTextOfLatestToast();
            // Test if toast actually shows up
            Assert.assertTrue(toast.equals("button clicked"));
        }
    }

This test case tests if the toast actually gets shown when the button is clicked. You can test this during compile time itself without actually running it! Say, you forgot to call show() on the toast you created, the test case fails!!! So, you quickly fix it and done, you are ready!

This way, you can test almost all of your code with Robolectric Unit Tests. Tomorrow, when someone changes this code and forgets to put the toast back, this code fails and complains. Fixing which, ensures that no feature is broken. This is what gives you confidence to drive and develop your code faster and better.

I will show you how to configure your application to write Unit Test cases in my next Robolectric tutorial.

Please leave the remarks, if any, in the comments section below. Thank you.

HAPPY CODING...!!

3 comments: