MVVM architecture, ViewModel and LiveData (Part 1)

During Google I/O, Google introduced architecture components which includes LiveData and ViewModel which facilitates developing Android app using MVVM pattern. This article discusses how can these components serve an android app that follows MVVM.
Read my full article:
https:[email protected]/mvvm-architecture-viewmodel-and-livedata-part-1-604f50cda1

Mockito 2.x over PowerMock Migration Tips and Tricks (Top Ten)

After so many years of hopeless waiting, Mockito 2.x is released to solve many problems that most of the android developers were having in their tests.

There are great features of Mockito 2.x which includes:

  1. Finally mocking final classes and methods.
  2. Support for Java 8.
  3. Migration from CGLIB to ByteBuddy.

But if you are having today large tests written in Mockito 1.x, will it be an easy task to migrate?

Unfortunately, the migration most probably will be a painful task because Mockito 2.x does not respect the old behavior of Mockito 1.x. Adding to this complexity, If you are having PowerMock in your old tests, then you will have to face another dimension of complexity since most of PowerMock’s versions are having integration issues with Mockito 2.x.

Regarding PowerMock’s early issues with Mockito 2.x, PowerMock team announced that PowerMock 1.6.5 has an experimental support for Mockito 2.x but unfortunately it was not that great. It has some problems with Mockito 2.x.

In the beginning when just changing Mockito version to 2.x in your build.gradle file, you may find more than 50% of your tests were failing due to a lot of issues, Null pointer exceptions, compilation errors, No class definition found, un-expected thrown exception, …etc, and this is how you may look in the beginning of the migration.

Do not panic and do not be sad, this blog post mentions some of the important challenges that you may face during the migration and tips to overcome these challenges to save your time.

1. Use the proper PowerMock’s Mockito API extension

Using powermock-api-mockito extension does not work with Mockito 2.x, you will have the following exception when running your unit tests if you stick to the old extension:

java.lang.NoClassDefFoundError: org/mockito/cglib/proxy/MethodInterceptor
at org.powermock.api.mockito.internal.mockmaker.PowerMockMaker.<init>(PowerMockMaker.java:43)
...
Caused by: java.lang.ClassNotFoundException: org.mockito.cglib.proxy.MethodInterceptor
at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
... 40 more

In order to fix this issue, you should use the right Mockito’s API extension which is:
powermock-api-mockito2.

2. Avoid using Incompatible versions of Mockito and PowerMock

Always make sure to use compatible versions of Mockito and PowerMock, for example the following two versions are compatible:

  • PowerMock version 1.7.0 RC2.
  • Mockito version 2.1.0.

3. Say Goodbye to Mockito’s Whitebox

Mockito 2.x does not have Whitebox anymore.

So what is the solution then?

Initially, you can use PowerMock’s Whitebox instead of the removed Mockito’s 2.x Whitebox. However, you need to know that this does not come without problems, one of the problem which I reported to PowerMock’s issues is (org.powermock.reflect.exceptions.FieldNotFoundException: No instance field named XXX could be found in the class hierarchy):
https://github.com/powermock/powermock/issues/773

So if the initial solution does not work with you, why not writing your own one, it is not really hard.

4. Using the Right Matchers

Never forget to always use org.mockito.ArgumentMatchers instead of the old org.mockito.Matchers.

For example, replace the old matcher imports:

import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyBoolean;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;

With the following ones:

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;

And so on with other matchers.

5. anyInt() does not match Long literals anymore

After the upgrade, you may find anyInt() does not work because it cannot match long literals such as 0L for example :).

So in order to fix this issue, just replace anyInt() with anyLong() and you will be fine.

OT note, if you can match with the actual value instead of anyXXX(), this can be much better and will give your test more transparency.

6. anyString() does not now match null anymore

This can fail many tests, anyString() now does not include null anymore in Mockito 2.x. This applies also to any(xxx), for example, any(InputStream.class) does not now match null in Mockito 2.x as well.

Again OT note, if you can match with the actual value instead of anyXXX(), this can be much better and will give your test more transparency.

7. Mockito 2.7.1 is not a real friend to PowerMock

Unfortunately, if you use PowerMock 1.6.5 or even PowerMock 1.7.0RC2 with Mockito 2.7.1 (the latest version at the time of writing this post), you will find the following exception with donothing:

java.lang.IllegalAccessError: 
tried to access method 
org.mockito.internal.stubbing.answers.DoesNothing.<init>()V from 
class org.powermock.api.mockito.PowerMockito

Fortunately, this issue is fixed with PowerMock 1.7.0RC4, and below is the fix issue URL for your information:
https://github.com/powermock/powermock/issues/753

So in summary if you use Mockito 2.7.1, do not forget to use PowerMock 1.7.0RC4.

8. Original test exceptions are wrapped as RuntimeExceptionProxy in Mockito 2.x with PowerMock

Unfortunately as a workaround, you have to modify all the broken @Test(expected=SomeException.class) to @Test(expected=Exception.class) since original exceptions are wrapped as Mockito RuntimeExceptionProxy in Mockito 2.x with PowerMock.

This issue really requires further investigation to know why Mockito 2.x does this wrapping with PowerMock. if you have a better solution for this, feel free to comment to the post.

9. Move away from PowerMock and depend on Mockito 2.x only

Try to create a plan to remove PowerMock by refactoring your app classes to be testable. Mockito 2.x is really enough now.

10. Review old tests

Take this migration as a chance to review the old tests and to improve them in order to have a better maintainable tests. This can help you strengthen your product code and allow easier refactoring for the current code base without surprises.

Android Mutation Testing – Back from AnDevCon SFO 2016

I just get back from AnDevCon that was be held from 29 November to 01 December @San Fransisco, USA. The conference organization was good and I had the chance to meet community Android folks.

In AnDevCon 2016, I had the chance to talk about “Mutation Testing for Android” in 01 December.

My session video is uploaded below.

My session slides is uploaded below.

Speaking in AnDevCon SFO 2016

adc-sf2016-header

@Thursday, 01 December 2:15 pm – 3:30 pm, I will be speaking in AnDevCon SFO conference (that will be held from 29 November to 01 December @San Francisco, USA) about “Android Mutation Testing”. In my session, I will discuss unit testing frameworks in Android, traditional code coverage techniques and mutation testing using PIT. The session will be a practical one, it will have two demos:
http://www.andevcon.com/sf2016/speakers#HazemSaleh

At the end of the session, there is an award for the one who will solve a quiz.

I really wish to see all of you there in AnDevCon SFO 2016!

Some Thoughts about Android apps Stressful Testing

Mobile Apps Performance testing is one of the most important factors which can ensure that apps are really powerful and flexible enough to work on different set of devices. The importance of this topic appears clearly when there are a lot of vendors that produce many devices with many models and capabilities on the platform (which is the case for Android Platform). This article discusses important tips that should be followed for performing stressful Android app testing which are necessary before publishing apps to stores.

Android Monkey Tests

Monkey tests are special type of tests which test the app under certain stressful conditions such as touching screen so many times, they are very useful in detecting issues that does not follow happy path flow (most of the time).

Android monkey tests are really a powerful option for performing stressful testing for Android apps. It sends a pseudo-random stream of user events into the system, which acts as a stress test on the mobile app you are developing.

Using Monkey Tests

Using monkey tests is easy, you can launch the Monkey using a command line on your development machine or from a script. Because the Monkey runs in the emulator/device environment, you must launch it from a shell in that environment. You can do this by prefacing adb shell to each command, or by entering the shell and entering Monkey commands directly.

The following command runs Monkey tests in your app sending 500 pseudo-random events to it:
adb shell monkey -p your.package.name -v 500

More information about the command parameters can be found in:
https://developer.android.com/studio/test/monkey.html

Important Tips for having an efficient monkey test

1. Pin your App screen

Because a monkey test can send random events anywhere even outside the app. Your monkey tests can fail testing your app, so it is really recommended to pin app screen as follows (This procedure works for Android 5.0 Lollipop):
https://www.cnet.com/how-to/ho-to-pin-apps-in-android-5-lollipop/

2. Stress Complex Activities as much as you can

Sometimes, you may need to perform stress testing on specific activities of your app, this is very useful to identify problems as early as possible especially for complex activities.

In order to do this, you need to add the following intent-filter to your activity or activities:

<activity android:name="ComplexActivity">
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.MONKEY" />
    </intent-filter>
</activity>

Then from command line specify the category (-c) parameter as follows:

adb shell monkey -p your.package.name -c android.intent.category.LAUNCHER -c android.intent.category.MONKEY 5000 

This will run monkey tests on LAUNCHER and MONKEY activities.

3. Have different levels of stress tests until reaching your app limits

Generally, it is recommended to start your monkey tests with small number of events and then increase them a bit by bit until you reach the app limits.

Also it is recommended to use the --throttle (which represents a fixed delay between events) to slow down the monkey.

4. Integrate your monkey tests with your CI

Ideally, monkey tests have to run for many hours on CI night jobs in order to detect app problems under stress as much as possible.

Monkey tests scripts can be easily integrated with CI using Execute shell task.

5. Perform monkey tests on real devices as much as you can

At the end, performing monkey tests on real devices as well as emulators are needed to detect the maximum number of issues as early as possible.

Dagger 2, MVP and Unit Testing (PIT Mutation Testing) – Part 4

The previous three articles[1] showed an introduction to Dagger, MVP pattern, Espresso and more. This article focuses on introducing a powerful test coverage technique for ensuring that the app unit tests are strong enough.

Introduction to Mutation Testing

One of the golden standard test coverage techniques is mutation testing. The main idea of mutation testing is to perform byte code modifications (mutations) to your original app source code and then run your app unit tests to check if they are strong enough to fail as a result of these mutations.

The byte code changes in Mutation Testing are named as faults (or mutations). After applying the source code changes, if your tests fail then the mutation is killed, and if your tests pass then the mutation is lived.

So in summary, If your tests fail by source code mutations then this means that your tests are really strong, if your tests pass then this means you need to modify your tests to make them strong enough (The quality of your tests can be gauged from the percentage of mutations killed).

Why we need Mutation Testing

Mutation tests have an advantage over Traditional test coverage (i.e line, statement, branch etc) because it does not only measure which code is executed by your tests but also it checks that your tests are actually able to detect faults in the executed code. This gives a strong measurement to your developed unit tests.

PIT

PIT is one of the mutation testing systems for Java. It has several advantages:

  1. Fast to execute.
  2. Integrated with Java build tools (Ant, Maven and Gradle).
  3. Active.

More information about PIT can be found in:
http://pitest.org/

Android Integration

Unfortunately, the official PIT Gradle plugin does not work fine with Android Gradle projects:
https://github.com/szpak/gradle-pitest-plugin

However, thanks to one of the community member, this support is now possible using this fork:
https://github.com/koral–/gradle-pitest-plugin

Application Configuration

In order to configure Android PIT plugin with our Android Dagger app:
1. Add PIT plugin to your top-level build.gradle file:

classpath 'pl.droidsonroids.gradle:gradle-pitest-plugin:0.0.3'

2. Configure PIT plugin in your app build.gradle file:

pitest {
   targetClasses = ['com.test.xyz.daggersample1.ui.presenter.*']  /* specify target classes to be mutated */
   excludedClasses = ['**Factory*'] /* Exclude Dagger generated classes */
   pitestVersion = "1.1.0" 
   threads = 4 /* specify number of threads */
   outputFormats = ['XML', 'HTML'] /* specify output format */
}

Checking Results

After configuration, finally, we can execute PIT tests by running:

./gradlew pitest

You can pick the PIT tests report under build/reports/pitest.

The following figure shows the mutation testing report in our Dagger sample:
PIT Report

The following figure shows survived and killed mutants:
Mutants

FYI, in the mutation report, Light green shows line coverage, dark green shows mutation coverage, Light pink show lack of line coverage, and dark pink shows lack of mutation coverage.

Source code

App Source code is available in:
https://github.com/hazems/Dagger-Sample/tree/pit1/app/src/test/java/com/test/xyz/daggersample1/ui/presenter

Top-level Gradle file PIT configuration:
https://github.com/hazems/Dagger-Sample/blob/pit1/build.gradle

Module-level Gradle file PIT configuration:
https://github.com/hazems/Dagger-Sample/blob/pit1/app/build.gradle

In our next article, let’s see how to kill these survived mutants which makes our tests not strong enough!

[1] Previous articles:
http://www.technicaladvices.com/2016/03/05/an-introduction-to-dagger-2-android-di-part-1/
http://www.technicaladvices.com/2016/03/09/an-introduction-to-dagger-2-android-di-part-2/
http://www.technicaladvices.com/2016/04/07/dagger-2-mvp-and-unit-testing-android-di-part-3/

Reverse Engineering Android app binaries (APK) for Legitimate Analysis

Android APK
Finally, I have some chance to get back to blogging since I was very busy last month. Now, let’s go in the details in our today’s topic.

Sometimes, you may have a situation to reverse engineer your existing APKs for legitimate analysis reasons such as making queries on the app source (including used third party libraries) for getting more inside information.

This post shows you how to revere engineer an existing APK for the purpose of such good reasons (again for purpose of *good* reasons).

Detailed way / Using Mainly Three Tools

In order to reverse engineer an APK file from its source, you need to do the following:

  • Exploding APK
  • Extracting Java Classes
  • Decompiling Java Sources
  • Inspecting APK Content

Now, let’s go through them quickly.

Exploding APK

First of all, we need to explode the apk file to mainly the apk resources (assets, libraries, and manifest files).

In order to achieve this step, you need to download and use ApkTool which can be found in:
https://ibotpeaches.github.io/Apktool/

After downloading the jar, execute the library jar as follows.

java -jar apktool_2.2.0.jar decode --no-src myApk.apk

Note that if you do not specify the no-src parameter, then the Apk tool will decode sources and generate SMALI code (Not Java).

Extracting Java Classes

The second step is to convert the APK DEX file(s) into Java jar file(s). You will be find the DEX files whose names
are following classes(i).dex pattern under the exploded apk file directory (note that if your apk is multi-dex then beside the main classes.dex file, you can find classes2.dex, (and/or) classes3.dex … and so on).

In order to make this extraction, you can use a very good tool called (dex2jar) which can be found below:
https://sourceforge.net/projects/dex2jar/

Download the zip file and extract it, then run the dex2jar tool from command line as follows (assuming
that the dex2jar directory is directly located in the same level of the DEX file(s)).

sh d2j-dex2jar.sh ../myApk/classes.dex -o ../myApk/src.jar

Decompiling Java Sources

After having the jars, now we can simply decompile these jars into original Java sources. For this, we can use the command line Java Decompiler which is available in:
https://github.com/kwart/jd-cmd

For every jar we have, we can simply decompile it by running jd-cli as follows.

./jd-cli src.jar

Inspecting APK Content

Finally, we can inspect the APK content as much as we wish. For example, we can get all the strings in the content which are following a URL pattern by executing the following grep command on the exploded apk root folder.

grep -Eo '(http|https)://[^/"]+' -R .

This command will output the complete list of files whose contents are matching this grep regular expression.

Fast way / Using Jadx

Jadx is a powerful tool for directly converting an APK to its original sources, it can be found in:
https://github.com/skylot/jadx
So for our myApk.apk, all what we need to get its original source is to use Jadx tool as follows.

./jadx myApk.apk 

Executing the previous command will do all the previous explained three steps for you.

Now, we are done, see you in the next post.

Back from ApacheCon North America 2016

I just get back from ApacheCon North America that was be held from 11 May to 13 May @Vancouver, Canada. The conference organization was really great and there were a lot of attendees in the conference sessions.

HazemSaleh_ApacheCon2016

I had the chance to present “Advanced Apache Cordova” in 12 May, the session was interactive, contained three live demos and I was really amazed by the energy, enthusiasm, and responsiveness of the attendees during the session.

My session is uploaded below.

Finally, I would like to thank all the organizers of ApacheCon conference for making the conference looks so great.

Dagger 2, MVP and Unit Testing (Android DI) – Part 3

In the previous two articles, we had an introduction to Dagger 2 with simple introductory examples and know how to use Android Build variants with Dagger 2 to have different implementations that are switched automatically when the app is in the debug mode or in the release mode.

This article discusses using Dagger 2 with MVP (Model View Presenter) pattern, and unit testing our simple Dagger 2 app using Espresso.

MVP is a derivation of MVC (Model View Controller) design pattern, and its main purpose is improving separation of concerns in the presentation layer. In MVP, Model represents “Data”, Presenter talks with the model to get data then it formats the data to be displayed by the view, and finally View displays the formatted data and delegate event handling to Presenter.

We will modify a little bit the introduced app in the first two articles to allow the end user to enter whatever city name and his name to finally have a greeting message that contains the current weather information of his entered city.

App Structure

The following interaction diagram shows the main app flow in an abstract way.
Sample Dagger App Flow

As shown in the diagram, in order to get weather information for a user, MainActivity talks with MainPresenter. Then MainPresenter talks with MainInteractor. Finally, MainInteractor abstracts the calls to the app services (HelloService and WeatherService) and it returns the result to the MainPresenter that displays data on the MainActivity (which represents the View).

The next diagram shows the app structure, which is a self-explanatory.
App-Structure

Dagger 2 for Dependency Injection

Now, let’s see some of the important details of Dagger 2 components and subcomponents in our App. We mainly have a single Component (AppComponent), which is responsible for AppModule and ServiceModule modules. AppComponent class code is shown below.

@Singleton
@Component(modules = {AppModule.class, ServiceModule.class})
public interface AppComponent {

    MainActivityComponent plus(MainActivityModule module);
    Application application();
}

Dagger Subcomponent is defined using @Subcomponent annotation on an interface. The main difference between Dagger component and Subcomponent is that Subcomponent cannot live standalone and has to be defined as a method on an interface marked as @Component and that method should return the interface marked as Subcomponent. This is why MainActivityComponent plus(MainActivityModule module) method is defined in AppComponent since a Subcomponent will be defined for every activity in our app.

The next code snippet shows the AppModule class code, which provides instances of Application and Resources classes.

@Module
public class AppModule {
    DaggerApplication app;

    public AppModule(DaggerApplication application) {
        app = application;
    }

    @Provides
    @Singleton
    protected Application provideApplication() {
        return app;
    }

    @Provides
    @Singleton
    protected Resources provideResources() {
        return app.getResources();
    }
}

The next code snippet shows the ServiceModule class code, which provides instances of HelloService and WeatherService.

@Module
public class ServiceModule {

    @Provides
    @Singleton
    HelloService provideHelloService() {
        return new HelloServiceDebugManager();
    }

    @Provides
    @Singleton
    WeatherService provideWeatherService() {
        return new WeatherServiceManager();
    }
}

@ActivityScope custom scope is defined for every activity Subcomponent; the following code snippet shows MainActivityComponent code.

@ActivityScope
@Subcomponent(
        modules = {MainActivityModule.class}
)
public interface MainActivityComponent {
    void inject(MainActivity activity);
}

MainActivityModule will be responsible for providing instances of the MainActivity (which implements the MainView interface), and also instances of MainInteractor interface.

@Module
public class MainActivityModule {

    public final MainView view;

    public MainActivityModule(MainView view) {
        this.view = view;
    }

    @Provides
    @ActivityScope
    MainView provideMainView() {
        return this.view;
    }

    @Provides
    @ActivityScope
    MainInteractor provideMainInteractor(MainInteractorImpl interactor) {
        return interactor;
    }

    @Provides
    @ActivityScope
    MainPresenter provideMainPresenter(MainPresenterImpl presenter) {
        return presenter;
    }
}

Finally, the next code snippet shows the custom Application class code, which is used for initializing the AppComponent graph.

public class DaggerApplication extends Application {
    private static AppComponent appComponent;
    private static DaggerApplication instance;

    @Override
    public void onCreate() {
        super.onCreate();
        instance = this;
        initAppComponents();
    }

    public static DaggerApplication get(Context context) {
        return (DaggerApplication) context.getApplicationContext();
    }

    public AppComponent getAppComponent() {
        return appComponent;
    }

    public void initAppComponents() {
        appComponent = DaggerAppComponent.builder()
                .appModule(new AppModule(this))
                .build();

    }

    /**
     * Visible only for testing purposes.
     */
    public void setTestComponent(AppComponent testingComponent) {
        appComponent = testingComponent;
    }
}

Note that setTestComponent(AppComponent testingComponent) method will be used for testing purposes only to provide a mock implementation of the AppComponent class to test the app flow.

App Details

Now, let’s see some of the app details. The next code snippet shows MainView interface that defines the view methods of the MainActivity (MainView is implemented by MainActivity and extends OnInfoCompletedListener interface).

public interface MainView extends OnInfoCompletedListener {
    public String getUserNameText();
    public String getCityText();

    public void showUserNameError(int messageId);
    public void showCityNameError(int messageId);

    public void showBusyIndicator();
    public void hideBusyIndicator();

    public void showResult(String result);
}

OnInfoCompletedListener interface defines the information retrieval operation’s callback methods since this operation is asynchronous.

public interface OnInfoCompletedListener {
    public void onUserNameValidationError(int messageID);
    public void onCityValidationError(int messageID);
    public void onSuccess(String data);
    public void onFailure(String errorMessage);
}

The following code snippet shows MainActivity class. Note that ButterKnife provides @InjectView annotation. ButterKnife is a lightweight library that can be used for injecting User interface elements instead of doing this every time manually using findViewById() method of View class.

public class MainActivity extends AppCompatActivity implements MainView, View.OnClickListener {

    @Inject
    MainPresenter presenter;

    @InjectView(R.id.userNameText)
    EditText userNameText;

    @InjectView(R.id.cityText)
    EditText cityText;

    @InjectView(R.id.btnShowInfo)
    Button showInfoButton;

    @InjectView(R.id.resultView)
    TextView resultView;

    @InjectView(R.id.progress)
    ProgressBar progressBar;

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

        ButterKnife.inject(this);

        DaggerApplication.get(this)
                .getAppComponent()
                .plus(new MainActivityModule(this))
                .inject(this);

        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        showInfoButton.setOnClickListener(this);
    }

    // …

    @Override
    public void onClick(View v) {
        if (v.getId() == R.id.btnShowInfo) {
            presenter.requestInformation();
        }
    }

    @Override
    public String getUserNameText() {
        return userNameText.getText().toString();
    }

    @Override
    public String getCityText() {
        return cityText.getText().toString();
    }

    @Override
    public void showUserNameError(int messageId) {
        userNameText.setError(getString(messageId));
    }

    @Override
    public void showCityNameError(int messageId) {
        cityText.setError(getString(messageId));
    }

    @Override
    public void showBusyIndicator() {
        progressBar.setVisibility(View.VISIBLE);
    }

    @Override
    public void hideBusyIndicator() {
        progressBar.setVisibility(View.GONE);
    }

    @Override
    public void showResult(final String result) {
        resultView.setText(result);
    }

    @Override
    public void onUserNameValidationError(final int messageID) {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                hideBusyIndicator();
                showUserNameError(messageID);
            }
        });
    }

    @Override
    public void onCityValidationError(final int messageID) {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                hideBusyIndicator();
                showCityNameError(messageID);
            }
        });
    }

    @Override
    public void onSuccess(final String data) {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                hideBusyIndicator();
                showResult(data);
            }
        });
    }

    @Override
    public void onFailure(final String errorMessage) {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                hideBusyIndicator();
                showResult(errorMessage);
            }
        });
    }
}

One important thing to note here is that in the activity’s onCreate() method, MainActivityComponent is initiated using DaggerApplication.get(this).getAppComponent().plus(new MainActivityModule(this)).inject(this). When the show information button is clicked, requestInformation() of MainPresenter is called.

The next code snippet shows MainPresenter interface which has only one method.

public interface MainPresenter {
    public void requestInformation();
}

MainPresenterImpl class implements MainPresenter as follows.

public class MainPresenterImpl implements MainPresenter {
    private MainView mainView;
    private MainInteractor mainInteractor;

    @Inject
    public MainPresenterImpl(MainView mainView, MainInteractor mainInteractor) {
        this.mainView = mainView;
        this.mainInteractor = mainInteractor;
    }

    @Override
    public void requestInformation() {
        mainView.showBusyIndicator();
        mainInteractor.getInformation(mainView.getUserNameText(), mainView.getCityText(), mainView);
    }
}

As shown in the MainPresenterImpl‘s requestInformation() method, it calls mainInteractor‘s getInformation() method passing user name, city name, and the class instance (mainView) which implements OnInfoCompletedListener interface.

The next code snippet shows MainInteractor interface.

public interface MainInteractor {
    public void getInformation(String userName, String cityName, final OnInfoCompletedListener listener);
}

The next code snippet shows MainInteractorImpl class, which interacts with HelloService and WeatherService interfaces.

public class MainInteractorImpl implements MainInteractor {
    private static final String TAG = MainInteractorImpl.class.getName();

    @Inject
    HelloService helloService;

    @Inject
    WeatherService weatherService;

    @Inject
    public MainInteractorImpl() {
    }

    @Override
    public void getInformation(final String userName, final String cityName, final OnInfoCompletedListener listener) {
        final String greeting = helloService.greet(userName) + "\n";

        if (TextUtils.isEmpty(userName)) {
            listener.onUserNameValidationError(R.string.username_invalid_message);
            return;
        }

        if (TextUtils.isEmpty(cityName)) {
            listener.onUserNameValidationError(R.string.city_invalid_message);
            return;
        }

        Thread thread = new Thread(new Runnable() {

            @Override
            public void run() {
                try {
                    int temperature = weatherService.getWeatherInfo(cityName);
                    String temp = "Current weather in " + cityName + " is " + temperature + "°F";

                    listener.onSuccess(greeting + temp);
                } catch (InvalidCityException ex) {
                    listener.onFailure(ex.getMessage());
                    Log.e(TAG, ex.getMessage(), ex);
                } catch (Exception ex) {
                    listener.onFailure("Unable to get weather information");
                    Log.e(TAG, ex.getMessage(), ex);
                }
            }
        });

        thread.start();
    }
}

When information is retrieved, getInformation() method calls the onSuccess() method of the OnInfoCompletedListener interface if the operation succeeds. If getInformation() method fails, it calls onFailure() method of the OnInfoCompletedListener interface.

Now, let’s look into the services part of the app. The next code snippet shows HelloService interface.

public interface HelloService {
    public String greet(String userName);
}

HelloServiceDebugImpl implements HelloService (Note that this implementation is active only in app debug mode. For the app release mode, HelloServiceReleaseManager will be the implementation of HelloService interface).

public class HelloServiceDebugManager implements HelloService {

    @Override
    public String greet(String userName) {
        return "[Debug] Hello " + userName + "!";
    }
}

The next code snippet shows WeatherService interface.

public interface WeatherService {
    public int getWeatherInfo(String city) throws InvalidCityException;
}

WeatherServiceImpl class implements WeatherService interface as follows.

public class WeatherServiceManager implements WeatherService {
    private static final String TAG = WeatherServiceManager.class.getName();

    @Override
    public int getWeatherInfo(String city) throws InvalidCityException {
        int temperature = 0;

        if (city == null) {
            throw new RuntimeException(ErrorMessages.CITY_REQUIRED);
        }

        try {
            city = URLEncoder.encode(city, "UTF-8");
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException(ErrorMessages.INVALID_CITY_PROVIDED);
        }

        try {
            URL url = new URL("http://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20weather.forecast%20where%20woeid%20in%20(select%20woeid%20from%20geo.places(1)%20where%20text%3D%22" + city + "%22)&format=json&env=store%3A%2F%2Fdatatables.org%2Falltableswithkeys");
            HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();

            httpURLConnection.setInstanceFollowRedirects(true);

            httpURLConnection.setRequestMethod("GET");
            httpURLConnection.setRequestProperty("User-Agent", "Mozilla/5.0");

            // Receive response ...
            int responseCode = httpURLConnection.getResponseCode();

            InputStream is = httpURLConnection.getInputStream();
            InputStreamReader reader = new InputStreamReader(is);
            BufferedReader bufferedReader = new BufferedReader(reader);
            String line = "";
            StringBuffer sb = new StringBuffer();

            while ((line = bufferedReader.readLine()) != null) {
                sb.append(line);
            }

            bufferedReader.close();

            String result = sb.toString();

            int startIndex = result.indexOf("\"temp\":");

            if (startIndex == -1) {
                throw new InvalidCityException(ErrorMessages.INVALID_CITY_PROVIDED);
            }

            int endIndex = result.indexOf(",", startIndex);

            temperature = Integer.parseInt(result.substring(startIndex + 8, endIndex - 1));
        } catch (InvalidCityException ex) {
            throw ex;
        } catch (Exception ex) {
            Log.e(TAG, ex.getMessage(), ex);
        }

        return temperature;
    }
}

What WeatherServiceImpl does is to get the weather information using Yahoo weather APIs.

Unit Testing App using Espresso

Now, let’s see how to unit test our application using Espresso. The next code snippet shows how we create our own test custom dagger component and use it instead of the original app component to test the app flow.

@RunWith(AndroidJUnit4.class)
public class MainActivityTest {
    private static String GREET_PREFIX = "[Test] Hello ";
    private static int MOCK_TEMPERATURE = 65;
    private static String MOCK_NAME = "Hazem";
    private static String MOCK_PLACE = "Cairo, Egypt";
    private static String MOCK_GREETING_MSG = GREET_PREFIX + MOCK_NAME;
    private static String MOCK_WEATHER_MSG = "\nCurrent weather in " + MOCK_PLACE + " is " + MOCK_TEMPERATURE + "°F";

    private static String MOCK_RESPONSE_MESSAGE = MOCK_GREETING_MSG + MOCK_WEATHER_MSG;

    private static String TAG = MainActivityTest.class.getName();

    @Rule
    public ActivityTestRule<MainActivity> mActivityRule =
            new DaggerActivityTestRule<>(MainActivity.class, new DaggerActivityTestRule.OnBeforeActivityLaunchedListener<MainActivity>() {
                @Override
                public void beforeActivityLaunched(@NonNull Application application, @NonNull MainActivity activity) {
                    DaggerApplication app = (DaggerApplication) application;

                    AppComponent mTestAppComponent = DaggerMainActivityTest_TestAppComponent.builder()
                                                                                            .appModule(new AppModule(app))
                                                                                            .build();

                    app.setTestComponent(mTestAppComponent);
                }
            });

    @Singleton
    @Component(modules = {TestServiceModule.class, AppModule.class})
    interface TestAppComponent extends AppComponent {
    }

    @Module
    static class TestServiceModule {

        @Provides
        @Singleton
        HelloService provideHelloService() {
            return new HelloService() {
                @Override
                public String greet(String userName) {
                    return GREET_PREFIX + userName;
                }
            };
        }

        @Provides
        @Singleton
        WeatherService provideWeatherService() {
            return new WeatherService() {
                @Override
                public int getWeatherInfo(String city) throws InvalidCityException {
                    return 65;
                }
            };
        }
    }

    @Test
    public void greetButtonClicked() {
        onView(withId(R.id.userNameText))
                .perform(typeText(MOCK_NAME), closeSoftKeyboard());

        onView(withId(R.id.cityText)).perform(clearText(), typeText(MOCK_PLACE), closeSoftKeyboard());

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

        onView(withId(R.id.resultView)).check(matches(withText(MOCK_RESPONSE_MESSAGE)));
    }

}

In the test method greetButtonClicked(), a simulation for entering a username and a city is performed and then the show information button is clicked and finally the returned result is being tested against the mock message.

Check the app source code

All the source code of this Dagger 2 app can be found in:
https://github.com/hazems/Dagger-Sample/tree/dagger2-mvp-espresso1

Feel free to use and let me know if you have comments.

Finally, I hope that these three articles can provide a useful introduction to the cool Dagger2 DI framework.

An Introduction to Dagger 2 (Android DI) – Part 2

androidlogo1
In the previous article, we have a quick introduction to Dagger 2 with a simple introductory example. In this article, I will show you how to use Android Build variants with Dagger 2 to have different implementations (for the service interface) that are switched automatically when the app is in the debug mode or in the release mode.

First of all, under the release directory, let’s create a new component DaggerGraphComponent which extends from DaggerGraph as follows.

@Singleton
@Component(modules = {MainModule.class, ServiceModule.class})
public interface DaggerGraphComponent extends DaggerGraph {

    static final class Initializer {
        private Initializer() {
        }

        public static DaggerGraph init(DaggerApplication app) {
            return DaggerDaggerGraphComponent.builder()
                                             .mainModule(new MainModule(app))
                                             .build();
        }
    }
}

Secondly, create a service module which will be responsible for creating the instances of HelloService implementations (in debug and release modes).

For the release mode, ServiceModule provides only an instance of the HelloServiceReleaseManager class which implements HelloService.

@Module
public class ServiceModule {

    @Provides
    @Singleton
    HelloService provideHelloService() {
        return new HelloServiceReleaseManager();
    }
}

Below is HelloServiceReleaseManager simple implementation.

public class HelloServiceReleaseManager implements HelloService {

    @Override
    public String greet(String userName) {
        return "Hello " + userName + "! [Release]";
    }
}

Apply the same steps under the debug directory, in debug case, you can have a HelloServiceDebugManager class which implements HelloService interface as shown below.

public class HelloServiceDebugManager implements HelloService {

    @Override
    public String greet(String userName) {
        return "Hello " + userName + "! [Debug]";
    }
}

Make sure to have the following code hierarchy in release and debug.
Release Directory

Debug Screenshot

Running the project

Now, you can run the app in debug mode, and then enter some name and then click “Greet!” button, you will find the debug service response as follows.
Debug Mode

And then change the build variant to run the app in the release mode and do the same previous steps to see the results as shown below.
Release Mode

Checkout the code

Check the sample app code in GitHub:
https://github.com/hazems/Dagger-Sample/tree/dagger-sample2

What is next?

So in the next article, I will discuss how can we apply unit testing techniques for Dagger 2 applications. Stay tuned!