Writing Android Tests with Espresso Test Recorder

espresso_test_recorder

Testing tools for Android have been improving significantly in the last 2 or so years. Instrumentation and Unit testing is now way easier with the advent of the Android Testing Library. There are tons of sources on how to integrate and use these tools in your own apps including these samples from Google for examples on how to write your own tests.

Android Studio 2.2 Preview 3 was recently released. This preview in my opinion, comes with the most coveted Android Studio feature revealed at Google I/O this year, Espresso Test Recorder. The recorder allows you to click through your app UI as normal as it records events and it generates reusable and editable test code for you. You can also add assertions (though limited). The generated tests can be run locally, on your Continuous Integration server, or on Firebase Test lab.

Although the recorder is still in beta, I decided to see how easy it would be to mimic the same UI tests from the Android Testing Codelab as described here. If you have not gone through that Codelab I urge you to read it before continuing , you will thank me later.

Manually writing the Codelab UI tests took roughly 20 minutes when I attempted them the first time. I wanted to see how much time the Espresso Test Recorder would save me on writing the same 3 UI tests described in that Codelab, so here goes:

First you will need to clone the sample code with:

git clone https://github.com/googlecodelabs/android-testing.git -b step-7
Espresso Test 1: Opening the ‘Add Note’ screen

This test opens the app, clicks the “add note” button and verifies that the correct screen is being displayed.

Espresso Test 2: Adding a note

This test will open the ‘Add Note’ screen, enter some text, click the save button and verify that the saved note has been displayed.

Espresso test 3: Clicking a note

This test verifies that clicking a note will display the correct note on screen. You will need to uncomment all the commented out code in the NoteDetailFragment class for this test to work as shown in the video.

 

Limitations
  • One class per test – currently you can only record a single test method per class. This isn’t a real issue though it would be nice if you could have multiple tests in one test class.
  • Available assertions are limited from the UI – the preview build has a limited option of assertions you can  do with the UI, so you will still need to write some code if you’re working with say intended() & intending() matchers.
  • UI assertions seem limited to your own UI code – e.g. if you have payments within your app, you can’t click the buy or cancel buttons on the Google PlayServices payments dialog box.
  • Input detection for Webviews – it does not seem like you can handle input for webview text boxes or add assertions to them.
  • Advanced features like handling background tasks which you can do with Idling Resources is still something you will need to code manually

 

Even though it has limitations it works well for the most common UI tests. I can only imagine it will get better with time. This without a doubt will make it a lot easier to write UI tests for your applications. It’s not a silver bullet but it definitely cuts down on the amount of boiler plate code you need to write. Writing UI tests definitely sucks less with the recorder. It took me less than 5 minutes to write the same tests with a bit of editing of the generated code. 

It’s definitely a good time to be an Android developer and to be using Android Studio.

To the Android Studio team…

giphy

Live Templates: Logging with Android Studio

Android Studio

Android Studio comes with some pre-packaged Live Templates to make writing code fast. There are some logcat specific live templates that you could use in your classes to quickly write  code for logging. Below are some of the logging methods that I find invaluable.

  1.  logt (create TAG):
    TAG
  2. logm (Log.d  for method call including parameter):logm
  3. loge (Log.e):loge

The same can be done for logi,logv,logr.  I don’t know about you. These have saved me a couple of keystrokes…and extra libraries just for logging.  You can even create your own Live Templates if you want.

Did you know: Reusing native element attributes in Custom Views

Native Attributes in custom views

It’s interesting some of the little things you could take for granted and figure out while digging in the Android source code.  If you’ve ever created your own custom views in Android you’ll note that sometimes you might require to make your own custom element attributes to style the appearance of your view when its defined in an XML file/element. Did you know though that instead of recreating some common attribute you could reuse the built-in defined element attributes?

Instead of:

<resources>
   <declare-styleable name="MyAwesomeLabelView">
       <attr name="malv_text" format="string|reference"/>
       <attr name="malv_icon" format="reference"/>
   </declare-styleable>
</resources>

you could :

<resources>
   <declare-styleable name="MyAwesomeLabelView">
      <attr name="android:text" />
      <attr name="android:icon" />
   </declare-styleable>
</resources>

Pretty cool huh!?  Just don’t get carried away with this by “overriding” all the native attributes in your custom views styleable declaration.

Did you know: ContextCompat

Untitled

Lately I’ve been refactoring some old code and one of the common issues I found was about deprecated calls to methods in the Resources class. I use the getDrawable(int) and getColor(int) calls in a lot of places . The suggestion from lint is that I use the matching method calls with an extra Theme parameter for styling purposes.

If you’d rather have the system handle that extra parameters for you, then maybe ContextCompat is for you. ContextCompat will provide a theme styled for the specified Context’s theme.

Instead of:

<activity>.getResources().getColor(R.color.levelColor)

you would:

ContextCompat.getColor(<context>,R.color.levelColor);

The same applies for most of the deprecated methods in Resources like getColorStateList. Check out ContextCompat.

Simple SQL Provider (Easy way to write custom sql based Content Providers for Android)

todo

I’ve created a code-lab on how to integrate this into your code-base ( 7 mins tops)

Creating your own custom Content providers involves a lot of boilerplate. Managing updates and adding a new column can also be a pain. Its through this frustration that I created this simple sql provider library to help with dealing with creating your own sql based content providers fast and simple. I’ve created a code-lab on how to integrate this into your code-base ( 7 mins tops). You can also checkout the sample To-do list app to see how its integrated in that app.

All you need to do is annotate your classes and it will generate associated content provider class at compile time, with some utility methods to deal with insertion and querying.

Working with GuidedStepFragments on Android TV

guided_step_fragment

If you want to develop for Android TV and easily adhere to TV UI best practices then the Leanback support library is your best bet.

The recently released support libraries revision 23.2.0 added new functionality to the GuidedStepFragment to further help direct users through a series of decisions in order to accomplish a goal. So what changed ?

Get the sample project on Github from here.

Button actions.

Button actions where added to GuidedActions. The idea is to make it faster to confirm/submit an action without having to scroll down through all the other actions before you can continue with your decision making. The videos below might explain this better.

Before:

Now:

In-order to create a button action , you can overide the onCreateButtonActions method or use GuidedStepFragment.setButtonActions. You can then listen for the selected button by overriding onGuideActionClicked.

 

Editable description fields.

 

It’s now possible to input text in an action. I would not overuse this feature though on TV , ever tried entering your email on TV with a remote ? Use GuidedAction.Builder.descriptionEditable(true) to make your action editable. You can listen for completion on this field via onGuidedActionEditedAndProceed. I saw they also added GuidedAction.Builder.descriptionInputType . I cant seem to make it work with the default TV keyboard on an Android TV emulator though.

Guided Action SubActions

This has the fill of drop down lists to it. So yeah we have these now. All you need to do is use the GuidedAction.Builder.subActions method to add more ‘sub’ actions to your main action. You can listen for a selection on any one of your subactions by overiding GuidedStepFragment.onSubActionClicked.

 

GuidedDatePickerAction

Simply put , this is just a date picker within the action view, yay. Just like editable GuidedActions. You listen for completion from within the onGuidedActionEditedAndProceed method.

As is clearly evident. Theres a lot of  new features within this release. I have made a sample app to show how to implement these new actions within your app. Get the sample project on Github from here.

I’m sure I’ve missed a few. If any let me know in the comments below.

 

Jodatime vs ThreeTenABP (Android Date/Time tool comparison)

Reaching the infamous dex method limit kinda sucks. Which is why I started to trim libraries in my app instead of just going the Multidex route. With the help of this nifty APK method count tool , I’ve been able to identify some libraries I might reconsider using.

Jodatime has 4713 methods and ThreeTenABP has 2827 methods (debug apk)

I’ve been using the Jodatime port  for a while now. It makes dealing with date and time functionality easy. I came across ThreeTenABP which is an Android backport of  Java 8’s JSR310 implementation. The functionality between the 2 seems comparable for what I use Jodatime for in my app. What stood out for me though was the method count.

Comparing Jodatime  (2.9.2) and ThreeTenABP (1.0.3) , the latter has a significantly lower method count. Jodatime has 4713 methods and ThreeTenABP has 2827 methods (debug apk). That difference was big enough for me to consider replacing my implementation and it was not as painful as I anticipated. I went through Jodatime’s quick start guide and tried implementing the same examples using ThreeTenABP.

Jodatime:


DateTime dt = DateTime.now();
int jd = dt.getDayOfMonth();
int jm = dt.getMonthOfYear();
int jy = dt.getYear();
Log.d(TAG,"Joda : "+ dt.toString());
Log.d(TAG,"Joda : [day: "+jd+"] [month: "+jm+"] [year: "+jy+"]");
Log.d(TAG,"Joda : [day: "+dt.dayOfWeek().getAsText()+"] [month: "+dt.monthOfYear().getAsText()+"] [year: "+dt.year().getAsText()+"]");
dt.withYear(2000);
dt.plusHours(2);
Log.d(TAG,"Joda : "+dt.toString());
String frenchShortName = dt.monthOfYear().getAsShortText(Locale.FRENCH);
boolean isLeapYear = dt.year().isLeap();
DateTime rounded = dt.dayOfMonth().roundFloorCopy();
Log.d(TAG,"Joda : [french Short: "+frenchShortName+"] [leapyear: "+isLeapYear+"] [rounded: "+rounded+"]");
dt = new DateTime(2005, 3, 26, 12, 0, 0, 0);
Log.d(TAG,"Joda : "+ dt.toString());
DateTime plusPeriod = dt.plus(Period.days(1));
Log.d(TAG,"Joda : +1day "+ plusPeriod.toString());
DateTime plusDuration = dt.plus(new Duration(24L*60L*60L*1000L));
Log.d(TAG,"Joda : +24h "+ plusDuration.toString());
DateTime today = DateTime.now();
DateTime yesterday = today.minusDays(1);
Hours diff = Hours.hoursBetween(today,yesterday);
Log.d(TAG,"Joda : hours between "+ diff.getHours());

ThreeTenABP:


LocalDateTime ldt = LocalDateTime.now();
int ld = ldt.getDayOfMonth();
int lm = ldt.getMonthValue();
int ly = ldt.getYear();
Log.d(TAG,"3ten : "+ldt.toString());
Log.d(TAG,"3ten : [day: "+ld+"] [month: "+lm+"] [year: "+ly+"]");
Log.d(TAG,"3ten : [day: "+ldt.getDayOfWeek().name()+"] [month: "+ldt.getMonth().name()+"] [year: "+ldt.getYear()+"]");
ldt.withYear(2000);
ldt.plusHours(2);
Log.d(TAG,"3ten : " +ldt.toString());
String frenchShortName = ldt.getMonth().getDisplayName(TextStyle.SHORT,Locale.FRENCH);
boolean isLeapYear = false; // could not find a matching function
LocalDateTime rounded = ldt.truncatedTo(ChronoUnit.DAYS);
Log.d(TAG,"3ten : [french Short: "+frenchShortName+"] [leapyear: "+isLeapYear+"] [rounded: "+rounded+"]");
ldt = LocalDateTime.of(2005, 3, 26, 12, 0, 0, 0);
Log.d(TAG,"3ten : "+ ldt.toString());
LocalDateTime plusPeriod = ldt.plusDays(1);
Log.d(TAG,"3ten : +1day: "+ plusPeriod.toString());
LocalDateTime plusDuration = ldt.plus(24,ChronoUnit.HOURS);
Log.d(TAG,"3ten : +24h : "+ plusDuration.toString());
LocalDateTime today = LocalDateTime.now();
LocalDateTime yesterday = today.minusDays(1);
org.threeten.bp.Duration diff = org.threeten.bp.Duration.between(today,yesterday);
Log.d(TAG,"3ten : hours between "+ diff.toHours());

You can get most of the functionality provided by Jodatime from ThreeTenABP. I also noticed that Jodatime now seems to have the JSR-310 implementations as well. The only reason I ended up changing was because of the method count. Your use case might vary to mine.

365BW : Version 3.2.6

365 Body Workout

So I finally managed to finish the sync across device functionality. You will be able to sync once cloud_syncyou login with your Google/Amazon credentials. On phone you can manually invoke sync from the action menus. Sync though happens
automatically every-time you create a custom workout or when you complete a workout session.

Get the new version now live on the PlayStore.