Wednesday, April 29, 2015

Google Hangout on Air from Google+ Pages

For the GDG Boulder meetup this Thursday, I would like to broadcast a Google Hangout on Air from the GDG Boulder G+ Page so that the recorded video will be saved to the GDG Boulder YouTube account. Took me a while to figure out the steps, so I want to document them here.

Prerequisite: You need to have a YouTube channel already linked to your Google+ page.

Switch to the Google+ Page

On Google+, click on your photo on the top right corner and switch to use Google+ as the Page admin.

Select "Hangouts" on the drop-down

Hover on the drop-down on the left, select "Hangouts".

Select "Hangout on Air"

Now you are on the Hangouts page as the Page admin. Select "Hangouts on Air" from the top tabs and you can now create a Hangout on Air as the Page admin!

Here is the Hangout on Air I created: https://plus.google.com/events/cgrute825m3sv909nd0da0if0ag

After you created your Hangout on Air, don't forget to enable the Q&A app. You won't be able to do that after the Hangout started.

Happy broadcasting!

Saturday, April 25, 2015

Espresso: Custom Idling Resource

One key feature in Espresso is the synchronization between the test operations and the application being tested. This is built around the concept of idling: Espresso waits until the app is "idle" before performing the next action and checking the next assertion.

Idle

What does it mean for the app to be idle? Espresso checks for several conditions:

  • There is no UI events in the current message queue
  • There is no tasks in the default AsyncTask thread pool

This takes care of waiting for the UI rendering and AsyncTask completion. However, if your app performs long-running operations in other ways, Espresso will not know how to wait for those operations to finish. If that is the case, you can tell Espresso to wait by writing a custom IdlingResource.

IntentServiceIdlingResource

Say you use an IntentService to do some long computation, and return the result to your activity via broadcast. We want Espresso to wait until the result is returned before checking that it was displayed correctly.

To implement an IdlingResource, you need to override 3 functions: getName(), registerIdleTransitionCallback() and isIdleNow().

@Override
public String getName() {
  return IntentServiceIdlingResource.class.getName();
}

@Override
public void registerIdleTransitionCallback(
    ResourceCallback resourceCallback) {
  this.resourceCallback = resourceCallback;
}

@Override
public boolean isIdleNow() {
  boolean idle = !isIntentServiceRunning();
  if (idle && resourceCallback != null) {
    resourceCallback.onTransitionToIdle();
  }
  return idle;
}

private boolean isIntentServiceRunning() {
  ActivityManager manager = 
    (ActivityManager) context.getSystemService(
      Context.ACTIVITY_SERVICE);
  for (ActivityManager.RunningServiceInfo info : 
          manager.getRunningServices(Integer.MAX_VALUE)) {
    if (RepeatService.class.getName().equals(
          info.service.getClassName())) {
      return true;
    }
  }
  return false;
}

The idle logic is implemented in isIdleNow(). In our case, we check if our IntentService is running by querying the ActivityManager. If the IntentService is not running, we can inform Espresso calling resourceCallback.onTransitionToIdle().

Register your idling resource

You need to register your custom idling resource in order for Espresso to wait for it. Do it in a @Before method in your test, and unregister it in @After.

@Before
public void registerIntentServiceIdlingResource() {
  Instrumentation instrumentation 
    = InstrumentationRegistry.getInstrumentation();
  idlingResource = new IntentServiceIdlingResource(
    instrumentation.getTargetContext());
  Espresso.registerIdlingResources(idlingResource);
}

@After
public void unregisterIntentServiceIdlingResource() {
  Espresso.unregisterIdlingResources(idlingResource);
}

Full example

Check out the source code for a full example. Try commenting out the IdlingResource registration and watch the test fail.

Source code: https://github.com/chiuki/espresso-samples/ under idling-resource-intent-service

Like this article? Take a look at the outline of my Espresso book and fill in this form to push me to write it! Also check out the published courses: https://gumroad.com/chiuki

Tuesday, April 21, 2015

Espresso 2.1: ActivityTestRule

When I wrote my android-test-demo app, I wanted to use Jake Wharton's ActivityRule, but couldn't because I wanted to customize the launch intent for each test method.

Today I got my solution from Google: Test rules in Espresso 2.1. ActivityTestRule can be configured to take a different launch intent per test method like this:

@Rule
public ActivityTestRule activityRule = new ActivityTestRule<>(
    MainActivity.class,
    true,    // initialTouchMode
    false);  // launchActivity. False to set intent per method

I then supply a launch intent in the test method:

@Test
public void intent() {
  DateTime dateTime = new DateTime(2014, 10, 15, 0, 0, 0);
  Intent intent = new Intent();
  intent.putExtra(MainActivity.KEY_MILLIS, dateTime.getMillis());

  activityRule.launchActivity(intent);

  onView(withId(R.id.date))
      .check(matches(withText("2014-10-15")));
}

See MainActivityTest.java for more details.

ActivityTestRule makes tests much cleaner. Thank you Google for making Espresso better and better!

Like this article? Take a look at the outline of my Espresso book and fill in this form to push me to write it! Also check out the published courses: https://gumroad.com/chiuki

Saturday, April 18, 2015

Espresso book?

I have been using Espresso for more than a year now, and I love it. I am considering writing a book / recording a video class / giving talks & workshops on the topic, but it is a substantial amount of work so I want to gauge interest before I start. If this material is valuable to you, please let me know by filling this form.

The outline

Introduction

  • What is instrumentation testing?
  • What is Espresso?
  • Basic anatomy of an Espresso test

ViewMatchers

  • How do matchers work?
  • Combining matchers (Hamcrest & Espresso)
  • Matching inside an AdapterView
    • onData
    • onChildView
    • inAdapterView
  • Using RecyclerViewActions with RecyclerView
  • Custom matchers

ViewActions

  • click(): What happens behind the scene?
  • Custom actions
    • getConstraints()
    • perform()

ViewAssertions

  • matches(ViewMatcher)
  • doesNotExist()
  • Custom assertions

Intents

  • Incoming: setActivityIntent
  • Outgoing: ActivityMonitor

App synchronization

  • The notion of idling
  • Custom IdlingResource

Repeatable tests

  • Avoid external dependencies (network, device configuration etc)
  • Dagger and Mockito

Cast studies

  • Combining various techniques in real-world scenarios

Your input

As a start, I submitted a talk proposal to Droidcon NYC. Please fav this tweet if you want to hear it:

However, the talk is only 40-minute long, highlighting maybe a quarter of this outline. It will take a lot more effort to flesh out the whole outline, so please let me know your interest by filling in this form: http://bit.ly/1H0X4up. Thank you!

Update: I have started publishing Espresso courses! https://gumroad.com/chiuki. Still trying to figure out what topics to tackle next, so I'd really appreciate your input.

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:

Wednesday, March 25, 2015

GHC proposals: Rejection likely

The Call for Participation for Grace Hopper Celebration just closed last week, and I saw a flurry of proposal submissions on Twitter. I am very excited to see so many people stepping up to speak, but I have some bad news:

Your proposal will probably be rejected
Your proposal will probably be rejected

GHC attracts a lot of proposals. A lot. Women from all walks of computing submit their talk ideas. In the past years I have heard a lot of excellent proposals being rejected. Bottom line, it is a very competitive process.

Don't waste your proposal

Now that you have written your proposal, you should submit it to other conferences. There are always conferences looking for speakers. Some resources:

Still not sure? Tweet me and I will recommend conferences to you.

Monday, March 23, 2015

Sketchnoting: An Engineer's Approach

Write/Speak/Code is the first conference I tried sketchnoting, and people loved it. I was really surprised because I still consider myself someone who cannot draw, but somehow I am good at sketchnoting. How come?

Constraint satisfaction problem

Naturally, I will explain my approach with a sketchnote:

When I took Alexis' sketchnotes class three years ago, I was really hung up on the idea that I needed to draw. The repertoire of shapes and objects that I can draw is really small, so I never actually tried sketchnoting after the class.

What changed? I flipped the problem around. I phrased it as a constraint satisfaction problem. I am using a small toolbox to express ideas I heard. And as an engineer, I am extremely good at that.

In the sketchnote above, I wanted to convey the idea that illustrations do not need to be realistic. At first I wanted to draw two trees, one realistic, one not. But alas, I cannot draw a realistic tree. Instead of giving up, I worked around by drawing a box with a dotted line to represent the realistic tree that I am unable to draw. Problem solved.

I am not kidding when I say my toolbox is small. You can see it in the sketchnote. The plain old notes vs sketchnotes part. That is literally my toolbox.

Use a pen

The other breakthrough came when I saw The Sketchnote Handbook by Mike Rohde in my local library:

The most important thing I picked up from the book is to use pen instead of pencil. This forces me to always make progress instead of erasing and re-drawing and second-guessing myself. It also makes me more forgiving of my mistakes, and come up with creative ways to fix them.

In the toolbox about bullet lists, I made two bullets with stars, because a single bullet doesn't make a list. And then I realized that I have nothing to more to say. What to do? The second star was already drawn. With ink.

I ended up writing "There is no second point" next to the second star. And you know what? It now emphasizes the fact that it doesn't take much to make sketchnotes.

A lot of serendipity came from using a pen and being forced to make things work.

Find your style

I really enjoyed the The Sketchnote Handbook because it includes examples from many sketchnoters. I pick and choose techniques that works for me:

  • Some sketchnotes are very free form, popping images left and right seemingly randomly. That terrifies me. But many examples use a grid style. I came up with my own layout algorithm: top to bottom, and if an item took too little horizontal space, put something next to it. This is very similar to traditional note taking, just using a bit more horizontal space. I can do that.
  • Some sketchnotes fill the whole page, and the pressure to do so paralyzes me. But many examples have whitespace between the items, and that is totally okay.
  • The book recommended using a vertical layout for panels, drawing the face of one panelist on each column. There is no way I can draw portraits. So I skipped that part. But it also showed a few simple ways to draw people. Now Starfish Man is a regular cast member in my sketchnotes.

Share

This is the most potent motivator: Twitter. You know how some people take a screenshot of a block of text to get around the 140 character limit? That looks stupid. But I can totally post a sketchnote to stuff more content into a tweet. And it looks awesome. So awesome that I get lots and lots of retweets, which gave me the confidence to do more sketchnotes, which gets more retweets.





Gotta love that positive feedback loop!