Sunday, November 2

Monday, October 13

Spoon screenshot current activity and change orientation

One of the problems I was having with espresso was to take screenshots of the current activity. With Espresso I can navigate and verify the views on screen, but once I move from one activity to another, the getActivity() function of the ActivityInstrumentationTestCase2 was still returning the activity declared in the class.

I saw that robotium has a function like that, but I wanted to have the same for espresso.

Denys in his post show a simple function to active this http://qathread.blogspot.com.br/2014/09/discovering-espresso-for-android-how-to.html , I will replicate it here:


 public Activity getActivityInstance(){  
   getInstrumentation().runOnMainSync(new Runnable() {  
     public void run() {  
       Collection<Activity> resumedActivities = ActivityLifecycleMonitorRegistry.getInstance().getActivitiesInStage(Stage.RESUMED);  
       for (Activity act: resumedActivities){  
         Log.d("Your current activity: ", act.getClass().getName());  
         currentActivity = act;  
         break;  
       }  
     }  
   });  
   
   return currentActivity;  
 }  

So now I can use


 Spoon.screenshot(getActivityInstance(), "screenshot_name");  

Nice =).

Also, if I want to see how the screen looks in landscape, I can do:

 getActivityInstance().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);  

And rotate it back if needed. Cool.

!

Sunday, October 12

Robolectric + Espresso + Spoon

I want to share how I configured my environment to use Espresso + Spoon and Robolectric together, and a little about how I'm using them in my projects.

This configuration is for Android Studio 0.8x with gradle.

First, Espresso.

Espresso


You can get the port of it for gradle from Jake Wharton Double Espresso project https://github.com/JakeWharton/double-espresso .

It seems that there is a bug in the android plugin, that will keep giving you a error like ' java.lang.IllegalAccessError: Class ref in pre-verified class resolved to unexpected implementation ' . To fix that you have to exclude specific conflicted dependencies between the app and the test app, as explained by Jake.

The tests for espresso need to be placed at the androidTest folder of your app module.

 

Robolectric


Because of this conflicts, I was unable to configure Robolectric together with Espresso in the way that the robolectric example shows https://github.com/robolectric/deckard-gradle , probably because of my project configuration.

Looking for a solution in the web, I found the project of nenick (https://github.com/nenick/android-gradle-template), promising a quick project template with espresso, robolectric, and other cool tools configured. Although it looks great, I didn't test the template itself (because I was trying to configure for an existing 'big' project), I was able to find the solution he used to configure robolectric.

Nenick points to different solutions he tried to configure robolectric and espresso https://github.com/nenick/android-gradle-template/wiki/Different-appraoaches-to-combine-Robolectric-&-Espresso . 
I tried to replicate some of them, but in the end, I was able only to use the same solution he did, that was to use novoda plugin https://github.com/novoda/gradle-android-test-plugin. 

This plugins allow you to configure robolectric in a different module, and them helps the separation of the test dependencies. 

The only annoying issue is that you need to compile the latest version, 0.9.9, because it is not yet published. To do this you can follow the script that nenick has in his project  Scripts/install-custom-gradle-test-plugin.sh https://github.com/nenick/android-gradle-template/blob/master/Scripts/install-custom-gradle-test-plugin.sh


In the end I installed it to my local maven repository, and them extracted to a local repository inside the project, that is references in the build.gradle, without the need to have a script for new installations.

To run robolectric tests (unit/integration tests) then you can just use: gradle testDebug

The tests will be placed inside the test folder of the java module you created to hold robolectric.

 

Spoon


After this, Spoon is easy. https://github.com/stanfy/spoon-gradle-plugin .
Then to run the espresso tests using spoon I just type gradle spoonDebug.

And...

I still need to know a way to configure a common test module to be used by the espresso and robolectric tests. Sometimes I keep repeating code to fake some objects in both places.

Also, I probably need to keep a better separation of what I should test using robolectric, and what I should test using espresso, because robolectric can test UI interaction, most of the time. I'm starting to think like this:
  • use unit tests whenever possible (inside the robolectric module, but NOT USING robolectric runner) . Keep a good separation of domain rules inside a specific layer, DO NOT PUT LOGIC INSIDE ACTIVITIES. I'm also trying to put any android specific code separated from main domain layer. Then I test all my domain layer using unit and junit integration tests.
  • Use robolectric for specific integrations. For now I only have database integrations tests, and async tasks tests at this level. Some networking can be put here too. But all robolectric tests I considered to be INTEGRATION TEST, because all that robolectric does is to enable android code to be ran locally, and you should not require this by any of your domain objects. So just use it for some boundary tests.
  • Espresso + Spoon for UI interaction. I'm using it currently for any UI interaction and views verification. I also use spoon to take screenshots so I can manually verify the design of the application and if the elements positions are ok. Although an idea was to have only specific UI codes here, I also exercise all the layers, with real database or network. Sometimes I mock.
I will see how this configuration evolves for me, and if any other tool or practice is a better fit. I'm trying something like ATDD for now, so, write the espresso test, write the integration/unit tests, write the code, pass the tests, refactor.

Finally, I have code coverage (emma) configured for my unit/integration tests, but I hope I can also get coverage feedback from espresso tests.

!