Random Quiz.

A example Android App making use of the MVP pattern, dependency injection with tests.

Posted by Matthew Regis on Wed, Dec 28, 2016
In Development, Android, Java
Tags java, android, mvp, testing, development, dagger 2, butterknife, timber, realm, mockito, gson, android async http

Cutting to the chase

If your like me you just want to see it working and play with the code. So here are the following links:

Introduction

I wanted to create a blog about Android development, so I created a app and open sourced it. In no way does this app demostrate every best practice for Android but it does demostrate a few. Best practices are constanlty changing and I feel what I have created here will change in 2 years time to something more of a MVVM pattern, that is if there is a good libary that allows you to do that or if Google make it part of core Android.

Android has many good example projects out there, but some examples encoroge bad practices that can lead to code becoming unmanageable. Spaghetti code is one way to call it, you don’t want this. I know for me the aim is to make my code base easy to work with now and in the future and one way to do this is too decouple and iscolate each part as much as you can so you single it off and test it.

In this blog I’ll go over the MVP pattern, dependency injection with tests.

MVP (Model View Presenter)

MVP is a software pattern that comes from MVC. I won’t bore you with the details, you can read about it here.

Some important things I like to try and remember about MVP

  • The view should not be concerned about the model.
  • The view basically should be dumb. No logic should live here.
  • Usually you don’t test the view because it is dumb.
  • The presenter should contain your logic, it’s what drives your view.
  • The presenter knows about the model and knows how to give it to the view.

Usually presenters and views are implemented with an interface and for example the presenter will interact with the interface.

A simple example:

Presenter interface

public interface ImainPresenter {
    void DoSomething();
}

View interface

public interface ImainView {
    void ShowSomething();
} 

Implementing a presenter

public class mainpresenter implements ImainPresenter{
  
  ImainView mMainView; // keep reference of the interface

  public mainpresenter(ImainView mainview){ // set the interface in the contructor
      this.mMainView = mainview; // mainview must implement ImainView in order for this to work
  }

  @Override
  void DoSomething(){ // implemented from the ImainPresenter interface
      mMainView.ShowSomething(); // calls a method from the ImainView interface
  }
}

Implementing a view with a activity

public class mainActivity extends Activity implements ImainView{
  Button but;
  ImainPresenter mMainPresenter; //keep reference to the presenter interface

  @Override
  protected void onCreate(Bundle savedInstanceState)
      super.onCreate(savedInstanceState);
      setContentView(R.layout.activity_main);
      but = (Button) findViewById(R.id.AButton)
      mMainPresenter = new mainpresenter(this); // set the presenter here, pass this(mainActivity) into the contructor which is ok because this implements ImainView 
    }

  @Override
  protected void onResume() { // on the onResume event call the presenters method DoSomething()
      mMainPresenter.DoSomething();
  }

  @Override
  void ShowSomething(){ //implements the method from the ImainView interface
      but.setVisibility(View.VISIBLE); 
  }
}

With the simple example above you can see things are set out more cleary. Seperation of concerns, the view is only concerned with the view and not any bussiness logic.

Using the MVP pattern you can see that it becomes easier to test the presenter because its defined what it should do. In the simple example above the mainpresenter’s method DoSomething() must call mainview’s ShowSomething().

I’ll give an example of a test using the simple example above later on.

Dependency Injection with Dagger 2

Again I won’t bore you with the details of dependency injection, you can read about it here.

What you should know about dependency injection is that it enables you to use your objects and classes to be used more freely in your project without concerning itself with having to create a object or class in order to work.

In the .Net world you could use Unity, Ninject and with .Net Core it’s baked into the product, which is good as it encorages good practices. In the Android world the only one worth mentioning as of now is Dagger 2.

You can find out more about Dagger 2 here. It’s worth mentioning that this was a fully supported project between Google and Square. It’s also worth mentioning Square probably make the most well used libaries in the Android world and you should check them out and also follow Jake Wharton who’s part of Square (he knows his stuff, others too but Jake is more well known).

I have to give credit to the following github repo’s for I have followed there examples in implementing dependency injection in a way that makes it more easy to maintain and build upon.

If you look in the source code for Random Quiz you will see this in the MainActivity. I have put comments with what’s injected and what makes the magic happen.

public class MainActivity extends BaseActivity implements IMainView {
    public final static String EXTRA_MESSAGE = "com.matthewregis.randomquiz.MESSAGE";

    @Inject MainPresenter mMainPresenter; // Using anotations to delcare what to inject

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        activityComponent().inject(this); // This is where the magic happens
        setContentView(R.layout.activity_main);
        ButterKnife.bind(this);
        mMainPresenter.attachView(this);
    }

And if you look at the presenter you will see this

public class MainPresenter extends BasePresenter<IMainView> {

    Context mContext;

    @Inject
    public MainPresenter(@ApplicationContext Context context){ // it injects the application context here 
        this.mContext = context;
    }

Here is another example with QuizPresenter.

public class QuizPresenter extends BasePresenter<IQuizView> {

    private Context mContext;
    private ILocalRepo mLocalRepo;

    OpentdbApi mOpentdbApi;
    Queue<ResultsBean> questions;
    List<Boolean> answered;

    GameMode mGameMode;

    @Inject
    public QuizPresenter(@ApplicationContext Context context, LocalRepo localRepo, OpentdbApi opentdbApi) {
        this.mContext = context;
        this.mLocalRepo = localRepo;
        this.mOpentdbApi = opentdbApi;
        this.initialize();
    }

You’ll be asking how does it know to inject Context, localReop and OpentdbApi. It knows how to do this because it was setup in ApplicationComponent here:

@Singleton
@Component(modules = ApplicationModule.class)
public interface ApplicationComponent {

    @ApplicationContext
    Context context();
    Application application();
    LocalRepo localReop();
    OpentdbApi opentbApi();
}

So when I declare a OpentdbApi and anotate it with @Inject Dagger 2 knows what to inject because i set it up above.

OpentdbApi looks like this.

@Singleton
public class OpentdbApi {

    Context mContact;
    AsyncHttpClient asyncHttpClient;

    @Inject
    public OpentdbApi(@ApplicationContext Context context){
        this.mContact = context;
        asyncHttpClient = HttpAsyncClientFactory.GetInstance();
    }

    public void Get10RandomQuestions(JsonHttpResponseHandler jsonHttpResponseHandler){
        asyncHttpClient.get(String.format("%s%s", mContact.getString(R.string.opentdb_base_url), mContact.getString(R.string.opentdb_random_10_path)), jsonHttpResponseHandler);
    }
}

You can see the @Singleton anotation which means I only want it to exsist once in my application life cycle. You can also see I inject the context into the contructor.

Testing with Mockito

Everyone wants to have a good code base and as few bugs as possible. To help with this you should create lots of tests to test your code.

When you test code you need to create other classes. For example when you test a presenter you need to create a view to test with but you don’t really care about the view, all you care about is the presenter and what it was supposed to do.

This is where mocking comes in handy. You can mock a class (in this case a view). It basically creates a fake object for you to test with. Also it will know what methods were called which is good for you to verify if a method was called from a presenter.

Here is an example from Random Quiz. Here you can see the @Mock notation above IMainView.

@RunWith(MockitoJUnitRunner.class)
public class MainPresenterTests {

    MainPresenter mainPresenter;

    @Mock
    IMainView mMainView;
    @Mock
    Context mContext;


    @Before
    public void SetUp() throws Exception{
        mainPresenter = new MainPresenter(mContext);
        mainPresenter.attachView(mMainView);
    }

    @After
    public void TearDown() throws Exception{
        mainPresenter.detachView();
    }

    @Test
    public void ShouldStartRandom10QuizOnRandomQuizBtnOnClick() throws Exception {
        mainPresenter.onRandom10BtnOnClick();
        verify(mMainView, times(1)).StartRandom10Quiz();
    }

    @Test
    public void ShouldStartSuddenDeathQuizOnSuddenDeathBtnOnClick() throws Exception {
        mainPresenter.onSuddenDeathBtnOnClick();
        verify(mMainView, times(1)).StartSuddenDeathQuiz();
    }

    @Test
    public void ShouldShowTopScoresOnTopScoresBtnOnClick() throws Exception {
        mainPresenter.onTopScoresBtnOnClick();
        verify(mMainView, times(1)).ShowTopScores();
    }
}

If we just look at this test.

@Test
    public void ShouldStartRandom10QuizOnRandomQuizBtnOnClick() throws Exception {
        mainPresenter.onRandom10BtnOnClick();
        verify(mMainView, times(1)).StartRandom10Quiz();
    }

I try to be descriptive in what the test should be. So in this case when I click on Random 10 the presenter should call StartRandom10Quiz(). Above you can see I use verify on the mocked object and I say how many times I expect it to be called and then what method.

So with that in mind here is an example test for the simple MVP pattern I implemented earlier on.

@RunWith(MockitoJUnitRunner.class)
public class mainpresenterTests {

    ImainPresenter mMainPresenter;

    @Mock
    ImainView mMainView; // here I create a mock main view

    @Before // this @Before anotation says to do this before running tests.
    public void SetUp() throws Exception{
        mMainPresenter = new mainpresenter(mMainView); // here I create the presenter and pass the mock view in
    }

    @Test // anotates a test
    public void ShouldCallShowSomthingOnDoSomthing() throws Exception {
        mMainPresenter.DoSomething();
        verify(mMainView, times(1)).ShowSomething();
    }
}

So hopfully DoSomething() will call ShowSomething() one time and the test will pass.

Summary

Before I followed examples and created all my code in the Activity or Fragment, now I know there’s a better way and hopfully if your reading this you do too.

If you want your Android code to be more clean, testable and more maintainable then use a pattern like MVP or MVVM. If you want to have as few bugs as possible then create lots of tests. Creating your app using MVP sets you up to do this.

Don’t just take my word for it, try it out and see for yourself. Take my example and hack it, build on top of it. I find there’s know better way to learn than to actually do it.


comments powered by Disqus