Bill Bejeck is a software developer and enjoys the challenges that software development brings. Bill also loves exploring new languages, technologies and learning and educating by blogging. Bill is a DZone MVB and is not an employee of DZone and has posted 29 posts at DZone. You can read more from them at their website. View Full User Profile

Android Unit Testing

10.08.2011
| 7159 views |
  • submit to reddit

This post is going to cover unit testing a native Android application.   While working on my own modest Android application, I wanted to add some non-instrumented unit tests and was surprised  how challenging it was to use mock objects.  Admittedly, instrumented tests running on a emulator or actual device is probably a better way to go, but I wanted a faster way to make sure that my internal logic was still working as expected when making changes.

Code Under Test

Here is one example of some of the code I was trying to test:

public class ViewOnTouchDragStartListener implements View.OnTouchListener {

    @Override
    public boolean onTouch(View view, MotionEvent motionEvent) {
        if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) {
            ClipData clipData = ClipData.newPlainText("", "");
            View.DragShadowBuilder dsb = new View.DragShadowBuilder(view);
            view.startDrag(clipData, dsb, view, 0);
            view.setVisibility(View.INVISIBLE);
            return true;
        } else {
            return false;
        }
    }
}

When I started writing my test method my plan was simple, just use Mockito to create mocks for the View and MotionEvent objects, set the expectations, run the test and watch the green bar. Instead all I received was a slew of RuntimeException(“Stub!”) errors. So I went back to the drawing board (Google) which led me to PowerMock. I have been using Mockito for some time now and I was aware of PowerMock that can be used to extend the capabilities of frameworks like Mockito and EasyMock to enable mocking of constructors, private methods and static methods among others. This seemed to be exactly what I was looking for to help with my Android unit testing issues.

Unit testing take two

I downloaded powermock-mockit-junit-1.4.10 (the most current as of this writing) There are also downloads available that work with TestNG and EasyMock. After some consultation with the documentation here is my improved unit test

@RunWith(PowerMockRunner.class)
@PrepareForTest({MotionEvent.class, ClipData.class,ViewOnTouchDragStartListener.class,View.class})
public class ViewOnTouchDragStartListenerTest {
    private ViewOnTouchDragStartListener dragStartListener;
    private View view;
    private MotionEvent motionEvent;
    private ClipData clipData;
    private View.DragShadowBuilder dragShadowBuilder;

    @Before
    public void setUp() throws Exception {
        dragStartListener = new ViewOnTouchDragStartListener();
        view = PowerMockito.mock(View.class);
        PowerMockito.mockStatic(ClipData.class);
        clipData = PowerMockito.mock(ClipData.class);
        motionEvent = PowerMockito.mock(MotionEvent.class);
        dragShadowBuilder = PowerMockito.mock(View.DragShadowBuilder.class);
    }

    @Test
    public void testOnTouchActionDown() throws Exception {
        PowerMockito.when(motionEvent.getAction()).thenReturn(MotionEvent.ACTION_DOWN);
        when(ClipData.newPlainText("", "")).thenReturn(clipData);
        PowerMockito.whenNew(View.DragShadowBuilder.class).withArguments(view).thenReturn(dragShadowBuilder);
        boolean isActionDown = dragStartListener.onTouch(view, motionEvent);
        InOrder inOrder = inOrder(view);
        inOrder.verify(view).startDrag(Matchers.<ClipData>anyObject(), Matchers.<View.DragShadowBuilder>anyObject(), eq(view),eq(0));
        inOrder.verify(view).setVisibility(View.INVISIBLE);
        assertThat(isActionDown,is(true));
    }

I found this fairly straight forward to implement, and best of all, I started getting green for all of my unit tests! I was impressed with PowerMock’s ability to mock out the constructor call to View.DragShadowBuilder inside the ViewOnTouchDragStartListener’s onTouch method (line 24 of test code sample and line 5 of the sample code, respectively). Admittedly, there probably should have been a separate method that would create and return the DragShadowBuilder object then use the PowerMock/Mockito spy functionality that allows you to selectively mock out methods on real objects.

Hopefully this will help you with your Android unit testing endeavors.

 

From http://codingjunkie.net/android-unit-testing/

Published at DZone with permission of Bill Bejeck, author and DZone MVB.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Tags:

Comments

Robert Craft replied on Thu, 2012/01/26 - 6:08am

Thank you for sharing. I struggled with the exact same problems. The Android testing framework, an integral part of the development environment, provides an architecture and powerful tools that help you test every aspect of your application at every level from unit to framework. The testing framework has these key features: Android test suites are based on JUnit. You can use plain JUnit to test a class that doesn't call the Android API, or Android's JUnit extensions to test Android components. If you're new to Android testing, you can start with general-purpose test case classes such as AndroidTestCase and then go on to use more sophisticated classes. The Android JUnit extensions provide component-specific test case classes. These classes provide helper methods for creating mock objects and methods that help you control the lifecycle of a component. Test suites are contained in test packages that are similar to main application packages, so you don't need to learn a new set of tools or techniques for designing and building tests. The SDK tools for building and tests are available in Eclipse with ADT, and also in command-line form for use with other IDES. These tools get information from the project of the application under test and use this information to automatically create the build files, manifest file, and directory structure for the test package. The SDK also provides monkeyrunner, an API testing devices with Python programs, and UI/Application Exerciser Monkey, a command-line tool for stress-testing UIs by sending pseudo-random events to a device.

Spring Security

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.