How to test a C.R.U.D. on android without affecting the main content of the app ?
I always wonder what everyone think about unit test. Some people said “Lopes, it is an excitement process, but I really don’ t know how to use it on my daily business Well … you should give it a try. Believe me ….
When you see a lot of system engineer looking at the same monitor. Well … “houston we have a problem here”
Unit Test on android
The picture below shows a short definition of instrumentation framework. According to android studio web site. This is the definition of instrumentation.
Android instrumentation is a set of control methods, or hooks, in the Android system. These hooks control an Android component independently of its normal lifecycle. They also control how Android loads apps.
The structure of project on android studio
All of unit test will be placed on folder androidTest. As soon as you read this post, you’ll see how to build a custom unit test.
Let’ s start writing some code ….
We will focus on Test case classes using JUnit3. First you should know how to writte a valid JUnit3 test. It is easy… take a look below.
public void test_first_test_case_1() {
//Logic goes here
}
public void test_first_test_case_2() {
//Logic goes here
}
As you can see to run a unit test, the methods must follow a simple framework convention. All methods must be public and start with the prefix “test” as you can see below. That’ s it ! The android studio will do some magic running and validating your code. Ah, before I forget , your code will run using the follow role.
- The JUnit3 will search for the first letter after the phase test
- The order will be in alphabetic order starting with A …. Z
- Must contain the follow struct: public void test
The class Assert
This class is used for “assert” your code. I will put some of the most used methods in my daily business.
Example of usage
output:
As expected, our test failed with a custom message. “Custom fail message”
Creating our first Project
Ok, let´s start our project. First I will explain our project. It will be a simple project with one table and a C.R.U.D. on this table.
Architecture
Ps. The atribute RG is like a personal ID
Initialising the Project
Let´s start writing some code. Open your Android Studio and select the given option as showed on the picture below
Tip: These steps will show how to create the database of application showing some tips along the post. You can skip these steps cloning the project on github
Fill all required field as below
Select next until the project has been created
Coding the project
First, create two packages with the names controller and database. Basically all business logic to create the database and do the C.R.U.D. will be placed in the package database and one layer above. It is used to insert some logic to call the class to insert or do some behavior will placed on controller. Check the topic architecture for more details.
Tip: You can use the plugin Sqlite Manager on firefox. It will help you to manager and create a database
Tip: For unit tests always create a Context passed by param. This stategy will allow to create a fake context. You will see this when I use the RenamingDelegatingContext class on Unit Test.
Create the package database with the class DatabaseConstants and insert the code using the link below. Copy and paste the code into your file DatabaseConstants. This class will be responsible to represent the table contact.
Code: Check the code in this link
In the package database create another class with the name DatabaseHelper. It will help us to manage the database sqlite3 of android. There are two required methods of the class SQLiteOpenHelper. The first one is onCreate and onUpdate. The first one is only called when your database has been created and the second one is called when the version of the database has been changed. For more details about this class, check this oficial link
Code: Check the code in this link
Tip: You should read about the Support Annotations. It is a great library that help us avoiding some commons problems like avoid to pass null object on methods. I will write another post about this library soon.
In the package database create another class with name ContactDAO. It will convert the object Contact to ContentValues and insert the row using an instance of SQLiteDatabase object.
Code: Check the code in this link
Before we continue with the next package, let´s do an overview about the package database.
- DatabaseHelper : This class is responsible for manager the access to database.
- DatabaseConstants : This class is responsible for mapping the table contact with its fields.
- ContactDAO : This class is responsible for convert the object Contact to ContactValues.
Our next step is to create another package with the name model and one class with the name Contact. This class will represent the table contact already created in the package database.
Code: Check the code in this link
That´s it ! You finished this package. Let´s go to the next one named controller. It will handle all your logic before inserting the content into the database.
First, create the package controller and one class with the name DatabaseController. It will be responsible for doing some logic before inserting the content using the contactDao. As our class is very simple, there is no hard logic on this class, but is it very helpful if you play with this class.
Code: Check the code in this link
Creating the Unit tests
This section explain in details how to create a unit test using the JUnit3. First, you need some important methods used on Junit3 as showed below.
The method setUp() always will be called when a test is runned. It will be the first method to be executed.
Example of usage:
- Configure the fake context to access the database.
- Restore an object or device to initial state
Tip: The second tip above is very common to be used when you are doing an integration test.
@Override
protected void setUp() throws Exception {
super.setUp();
}
The method tearDown() always will be called when a test has been finished.
@Override
protected void tearDown() throws Exception {
super.tearDown();
}
Let´s create a simple unit test to show the life cycle of JUnit3. On the project, create a classe with the name SimpleLog and extends it of AndroidTestCase as showed below.
Tip: The AndroidTestCase is a special class used to access the context of application providing access to assets, strings, dimens, drawable etc… of application.
Click on the context menu and select the option “run simple log” as showed below
You can check the output using the tag “test” on logcat. As you can see, both methods setUp and tearDow were called for each individual test.
Tip: You can run the logcat on command line using the command: adb logcat -s “TAG”:V
Creating the unit test of DatabaseController
On this step we will use the mocked context avoiding changing the main content of the app. First, let’s create a new class with the name DatabaseControllerTest on package br.lopes.unittest ( androidTest ). If you does not see this folder , it’ s necessary created it manually using the perspective Project on androidStudio as showed below.
After you have created the class extend it using the class AndroidTestCase Override the method setUp. On this method create an instance of class RenamingDelegatingContext. It will create a mocked context avoiding changing the main content of app/Database.
Tip: If you ran your unit test using the context getContext() of androidTestcase, it will change the main content of app. Always use the class RenamingDelegatingContext for test database
Create the first unit test . Let´s check if the object Contact was properly inserted. I’ ve used the Assert class a lot while checking the expected values.
Tip: If you don’ t have a device, you can use the genymotion to run your tests. It has a great performance.
Create the second unit test. Let´s check if we can fetch the inserted content properly
Create the third unit test. Let´s check if the content was deleted properly
Create the fourth unit test for. Let´s check if the result of an invalid row returns false
Create the fifth unit test. Let´s check if the content was updated properly
That’s it. You can play creating some unit test with the mocked context on this class. I recommend you to start coding first, it takes a few minutes to think about some possible scenarios for your tests. It will be helpful specially when writing some new features that may brake the ones that already exists.If you have some questions, please let me know.
My next post may be about support annotation or integration test with espresso. I will keep you in touch.
Thanks Felipe Vasconcelos , Ricardo ferreira and Carlos Ottoboni for your support.