Showing posts with label mocktio. Show all posts
Showing posts with label mocktio. Show all posts

Friday, November 6, 2015

MVP: The Missing Link

I have been wanting to learn the Model View Presenter pattern for a while, and was super excited to get Michael Cameron to give a talk on it at GDG Boulder last night.

View Interface

I have this vague notion that MVP is good for JUnit testing, and I finally figured out why. The secret, the missing link, is View Interface, which is not a part of the MVP acronym. View Interface defines the contract between the view and the presenter, allowing you to mock one while testing the other.

With View Interface, you can compartmentalize your Android UI code into the view (typically a Fragment or Activity), which communicates with your presenter solely through the View Interface. This separation allows you to mock your View Interface with zero Android code, which means you can test your presenter with JUnit on the JVM.

Mocking via build flavors

Mocking is essential for hermetic testing, but people are often intimated by dependency injection frameworks like Dagger. If you prefer, you can provide mocks to your test using build flavors. An excellent technique!

Mockito

Mockito is a great mocking framework with a fluent API. One very nice feature is mocking via annotations. To use that, annotate the fields you want to mock with @Mock, and initialize them all with MockitoAnnotations.initMocks() in your @Before function.

@Mock
private MyThing myThing;

@Mock
private OtherThing otherThing;

@Before
public void setUp() throws Exception {
  MockitoAnnotations.initMocks(this);
}

This is equivalent to:

private MyThing myThing;
private OtherThing otherThing;

@Before public void setUp() throws Exception {
  myThing = Mockito.mock(MyThing.class);
  otherThing = Mockito.mock(OtherThing.class);
}

Slides: http://www.slideshare.net/DarxVal/model-view-presenter-presentation

Codelab

Google has published the excellent Android Testing Codelab going through an app with the MVP architecture. You can see JUnit and Espresso testing in action, mocks via build flavors, and various other techniques. Go check it out!

Thursday, April 9, 2015

Dagger 2 + Espresso 2 + Mockito

I've been doing Android instrumentation testing with Dagger, Espresso and Mockito, and I love it. To commemorate the launch of Dagger 2 out of SNAPSHOT, I am sharing a demo repo with Dagger 2, Espresso 2 and Mockito:

https://github.com/chiuki/android-test-demo

Dagger Components

Dependency injection allows our app and test obtain different modules. This is very useful for creating repeatable test cases. The demo app displays today's date in the format yyyy-MM-dd. We would like to test that against a known date, instead of depend on the actual date when we run the test.

In Dagger 2, a Component provides modules for your whole app, and defines where to inject them.

public interface DemoComponent {
  void inject(MainActivity mainActivity);
}
@Singleton
@Component(modules = ClockModule.class)
public interface ApplicationComponent extends DemoComponent {
}
@Singleton
@Component(modules = MockClockModule.class)
public interface TestComponent extends DemoComponent {
  void inject(MainActivityTest mainActivityTest);
}

ApplicationComponent is used when the app is run normally, and TestComponent is used during tests. Both components injects into MainActivity.

How does the MainActivity know which component to use? It injects via the application, which stores the component.

Approach 1: setComponent

private DemoComponent component = null;

@Override public void onCreate() {
  super.onCreate();
  if (component == null) {
    component = DaggerDemoApplication_ApplicationComponent
        .builder()
        .clockModule(new ClockModule())
        .build();
  }
}

public void setComponent(DemoComponent component) {
  this.component = component;
}

public DemoComponent component() {
  return component;
}

We call setComponent() in test, which runs before onCreate(), so the TestComponent is used. When the app is run normally, component will be set to ApplicationComponent in onCreate().

Approach 2: Mock application

Exposing setComponent in the application is not great because ideally the application should not have test-specific code. Another approach is to subclass the application in the androidTest folder and load it during tests via a custom test runner. See blog.sqisland.com/2015/12/mock-application-in-espresso.html for more details.

Mockito

The app has a Clock class which returns the current time.

public DateTime getNow() {
  return new DateTime();
}

TestComponent contains MockClockModule, which provides Clock as mocked by Mockito. This way MainActivityTest can supply a pre-determined date during test.

Mockito.when(clock.getNow())
  .thenReturn(new DateTime(2008, 9, 23, 0, 0, 0));

Since we have singleton modules, the same mocked Clock is supplied to the app. With that, it will display the provided date instead of today's date:

onView(withId(R.id.date))
  .check(matches(withText("2008-09-23")));

More

There is a lot more in the repo, including testing activity launch with intent and unit testing with JUnit. Please check it out:

https://github.com/chiuki/android-test-demo

Look at the setComponent branch to see the old code for injection using the setComponent function. Master uses mock application and custom test runner for injection.

Also, I am toying with the idea of writing a book on Espresso. Please take a look at the outline and fill in this form if you think I should write it!

Update: I have started publishing Espresso courses! https://gumroad.com/chiuki

Further reading: