Testing(, with some examples in Android)

Hi, friends.

micro_controllerIt’s been a long time. But, hey… I’m back. I’ve been too busy trying to save my semester :V (Also, busy with microcontrollers. But that’s later.).

Today, I decided to come back with some high level stuff, which I haven’t been working on for some time. Let me ask you a question. How do you test your applications? (This is not only about Android applications. Your application can be a C program, too.) I’ve been coding Android applications for about 2,5 years, and for 1,5 years I’ve tested my applications by just using them myself. If my application didn’t behave as I wanted, that meant the tests were failed and I had to change my code to make it behave as I want. It’s pretty good for small projects. I actually recommend you to check every behaviour you implement as soon as you implement them. But it’s just not good enough when the project is pretty big. Sooner or later, we cannot keep track of all the features we implement and it becomes impossible to test every feature we implement. At that point, instead of testing every feature by hand, we decide to leave it to the computer. (Like it doesn’t have much work to do… poor machine :/)

Why? Because a machine can test an application better than us. It can always check for every feature we implement, and it does the job very quick. It also makes sure that we never break the old features as we implement new features. Only drawback is we have to tell what it has to test. We have to write every instruction to the machine, and tell what to expect, too. For example, if we have an application that displays a list of elements and it removes an element from the list whenever we tap on the element, we can write a test like this:

  • Actions:
    • Add 10 elements to the list. Name them “Element (n)”
    • Tap on “Element 3”
  • Conditions:
    • “Element 3” should not be in list.

This tests the remove behaviour. But what if the elements never gets added to the list? We can have a test case for that, too:

  • Actions:
    • Add 10 elements to the list. Name them “Element (n)”
  • Conditions:
    • “Element 3” should be in list.

You may want to check all 10 elements in the list, and that would be better. But I decided that this condition is okay for my test case. (Not that I just copied and pasted the test above and got too lazy to change a thing in it.)

That’s the basics of testing. Now let’s see some Android examples. I use Espresso Framework to test Android applications. It lets me write my tests just like list above. Watching the tests are amazing, too. I’ll put a video below just to show how amazing it is when the phone itself types 15 characters per second :D. But first let’s see how we setup the Espresso Framework.

By adding these lines to the gradle file of our app, and syncing the project, we will have our test framework ready.

dependencies {
    ...
    androidTestCompile 'com.android.support:support-annotations:23.4.0'
    androidTestCompile 'com.android.support.test.espresso:espresso-core:2.2.2'
    androidTestCompile 'com.android.support.test:runner:0.5'
}

You may wonder why did I added the support-annotations to test dependencies. That’s because of a dependency conflict between the app and the test modules. I don’t really know much about it but I think espresso uses an older version of support-annotations and it conflicts with the newer version in the app module. What I only know is that this fixes the problem, so it doesn’t really matter.

Now we can create classes in the androidTest build variant.

    package ...;

	import ...

	/**
	 * Created by triforce on 06/06/16.
	 */

	@RunWith(AndroidJUnit4.class)
	@LargeTest
	public class LoginActivityTest {

	    @Rule
	    public ActivityTestRule<UserLoginActivity> mActivityRule = new ActivityTestRule<>(UserLoginActivity.class);

	    public static final String LOGIN_EMAIL = "user@karacasoft.com";
	    public static final String LOGIN_PASSWORD = "1234";

	    @Test
	    public void loginTest() {
	        onView(withId(R.id.edt_email)).perform(typeText(LOGIN_EMAIL));
	        onView(withId(R.id.edt_password)).perform(typeText(LOGIN_PASSWORD));

	        onView(withId(R.id.btn_login)).perform(click());

	        SystemClock.sleep(2000);

	        assertTrue(mActivityRule.getActivity().isFinishing());
	    }

	    @Test
	    public void registerButton() {
	        onView(withId(R.id.edt_email)).perform(typeText(LOGIN_EMAIL));
	        onView(withId(R.id.edt_password)).perform(typeText(LOGIN_PASSWORD));

	        onView(withId(R.id.btn_register)).perform(click());

	        onView(withId(R.id.edt_password)).perform(clearText());

	        onView(withId(R.id.edt_email)).check(matches(withText(LOGIN_EMAIL)));
	        onView(withId(R.id.edt_password)).check(matches(withText("")));

	        pressBack();

	        onView(withId(R.id.edt_email)).check(matches(withText(LOGIN_EMAIL)));
	        onView(withId(R.id.edt_password)).check(matches(withText(LOGIN_PASSWORD)));
	    }


	}
    

We can use the @Rule annotation to set the Activity we want to test. The activity will be started for each one of the test cases. As you can see in the cases, Espresso lets me use some high level stuff to type text in EditText’s. Please check out the espresso documentations┬áto see more examples of the framework. I wonder how I never got bored of writing the same user email and password over and over.

Well, my friends, that’s all knowledge I have about testing. One thing you have to remember is that writing tests is a big time consumer. For small projects, it can even be bad to use test-driven development. But, try test frameworks in one of your projects. Having the idea of testing is always good, even if you don’t use tests in your project. Check out the video below to see how awesome it is to watch running tests. :V

Leave a Reply

Your email address will not be published. Required fields are marked *