Photo credit Pexels

Testing in Android with MVVM — Part 1

Test Driven Development or TDD in Android is something that everyone wants to do but its mostly ignored or set aside for the next cycle or quarter. The major reason for most people shying away from TDD in Android was that it was actually hard to do in Android. The practice of having the business logic tightly coupled with many of the Android components didn`t make it any easier too. But the recent shift in adopting more clean architecture and Google`s focus on making the testing tools more easier and accessible encourages us to take another look at TDD in Android.

Using some kind of UI architecture is essential for achieving TDD in Android. The Model View Presenter(MVP) and Model View ViewModel(MVVM) patterns are the most common ones used in Android development. We will be using the MVVM pattern in this example because MVVM allows us to separate business logic and states clearly into the View Model and also, MVVM has lesser boilerplate and ceremony around setting things up compared to other patterns like MVP, MVC etc. The separation of business logic and view states to the ViewModel enables us to write unit tests for the same easily.

MVVM — Model View View Model

MVVM pattern

Let’s take a look at the different parts that make the MVVM pattern.

Model — The model holds the data and also deals with persistence and syncing data to and from the server. The data persistence can be done through a local SQLite database, shared preference, content provider etc.

View — The view basically reacts to the view model and presents the interface to the user. Views are the part deals with the Android platform components and also closest to the end user. Anything related to Android like Activities, Fragments, Views etc comes under the category of views.

ViewModel — The view model holds the state of the current view and other data required to populate the view. The view model also contains the business logic required by the view and also enables communication between the View and Model layer.

Another important part of the pattern is the notifications layer will allows us to pass data between the MVVM layers. It can be implemented using traditional interfaces or using events or RxJava.

Let’s see how MVVM can be used to write more clean code that also makes testing easier on Android by building a simple registration screen. The complete code can be found here Github .

Our test registration screen

The main classes implementing this feature will be
--RegisterActivity
--RegisterScreen
--RegisterViewModel
--RegisterModel

The RegisterActivity and RegisterScreen will together form the View part and RegisterModel and RegisterViewModel will implement the Model and ViewModel respectively. The important thing to take note here is the RegisterScreen interface that defines a contract for the view class to implement. Since the view class is an implementation of a contract it can be mocked using Mockito or some other mocking framework for easy unit testing.

//RegisterScreen.java
public interface RegisterScreen extends Screen {

void showNameError();
void showPhoneError();
void showEmailError();
void showAddressError();

void showRegisterSuccess();
void showRegisterFailed();

}
//Screen.java
public interface Screen {

void showToast(String msg);

}

If you look at the RegisterActivity class, it’s a normal activity class that extends AppCompatActivity but additionally implements the RegisterScreen contract.

//RegisterActivity.java
public class RegisterActivity extends AppCompatActivity implements RegisterScreen {

RegisterViewModel registerViewModel;

public static void start(Context context) {
Intent starter = new Intent(context,RegisterActivity.class);
context.startActivity(starter);
}

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
    @Override
public void showToast(String msg) {
Toast.makeText(this, msg, Toast.LENGTH_SHORT).show();
}
}

The RegisterModel is a simple POJO class, that holds some data for us. In practice, the model could be querying, fetching or syncing data from the local DB, a REST API or just the shared preferences.

//RegisterModel.java
public class RegisterModel {
    private String name;

private ILogger log;

public RegisterModel(ILogger log) {
this.log = log;
}

public boolean isNameValid(){
if (Strings.isNullOrEmpty(name)){
return false;
}else {
return true;
}
}

public void register(){
log.d(TAG, "register() called");
}


//getters and setters
public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

}

The RegisterViewModel ties the View and Model together.

//RegisterViewModel.java
public class RegisterViewModel {

private RegisterScreen registerScreen;
    private RegisterModel registerModel;

public RegisterViewModel(RegisterScreen registerScreen,
ILogger logger) {
this.registerScreen = registerScreen;

this.registerModel = new RegisterModel(logger);
}
    public void doRegister(){
boolean hasError = false;

if (!registerModel.isNameValid()){
registerScreen.showNameError();
hasError = true;
}

if (hasError){
return;
}

registerModel.register();

registerScreen.showRegisterSuccess();
}

    public RegisterModel getRegisterModel() {
return registerModel;
}

}

One thing to take note in the RegisterViewModel is that the constructor is accepting an instance of the interfaces RegisterScreen and ILogger. This allows us to pass mocked implementations of them instead of passing an instance of the concrete implementation. This enables us to write unit tests that run on the JVM instead of writing Instrumentation tests that need and Android environment to run and takes a lot of time.

The rule of thumb while writing your app in the MVVM pattern is to keep all your Android imports in the view implementation alone. In cases where you cannot avoid importing from android for your ViewModel or Model implementation make an interface or wrapper that abstracts away the Android implementation. An example for that is the ILogger interface we use in the example.

The complete code for all the classes and interfaces can be found here.

In the next part, we will see how we can write unit tests using JUnit for the MVVM implementation that we have done now.