{"id":19169394,"url":"https://github.com/ravidsrk/android-testing-guide","last_synced_at":"2025-04-04T21:10:26.347Z","repository":{"id":75230893,"uuid":"67680403","full_name":"ravidsrk/android-testing-guide","owner":"ravidsrk","description":"[Examples] Complete reference for Android Testing with examples.","archived":false,"fork":false,"pushed_at":"2017-11-20T16:27:08.000Z","size":245,"stargazers_count":701,"open_issues_count":2,"forks_count":126,"subscribers_count":29,"default_branch":"master","last_synced_at":"2024-04-14T01:07:07.335Z","etag":null,"topics":["android-tests","instrumentation-tests","junit","mock"],"latest_commit_sha":null,"homepage":"http://ravidsrk.github.io/android-testing-guide/","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ravidsrk.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2016-09-08T07:41:00.000Z","updated_at":"2024-04-10T05:50:41.000Z","dependencies_parsed_at":null,"dependency_job_id":"f0ecdbef-0e05-42f7-a270-9b5b75b5e1f6","html_url":"https://github.com/ravidsrk/android-testing-guide","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ravidsrk%2Fandroid-testing-guide","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ravidsrk%2Fandroid-testing-guide/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ravidsrk%2Fandroid-testing-guide/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ravidsrk%2Fandroid-testing-guide/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ravidsrk","download_url":"https://codeload.github.com/ravidsrk/android-testing-guide/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247249532,"owners_count":20908212,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["android-tests","instrumentation-tests","junit","mock"],"created_at":"2024-11-09T09:46:56.147Z","updated_at":"2025-04-04T21:10:26.332Z","avatar_url":"https://github.com/ravidsrk.png","language":"Java","readme":"# Android Testing Guide [![Android Arsenal](https://img.shields.io/badge/Android%20Arsenal-Android%20Testing%20Guide-brightgreen.svg?style=flat)](https://android-arsenal.com/details/3/6473) [![Backers on Open Collective](https://opencollective.com/android-testing-guide/backers/badge.svg)](#backers) [![Sponsors on Open Collective](https://opencollective.com/android-testing-guide/sponsors/badge.svg)](#sponsors) [![Join the chat at https://gitter.im/android-testing-guide/Lobby](https://badges.gitter.im/android-testing-guide/Lobby.svg)](https://gitter.im/android-testing-guide/Lobby?utm_source=badge\u0026utm_medium=badge\u0026utm_campaign=pr-badge\u0026utm_content=badge)\n\n### Show some :heart:\n[![GitHub stars](https://img.shields.io/github/stars/ravidsrk/android-testing-guide.svg?style=social\u0026label=Star)](https://github.com/ravidsrk/android-testing-guide) [![GitHub forks](https://img.shields.io/github/forks/ravidsrk/android-testing-guide.svg?style=social\u0026label=Fork)](https://github.com/ravidsrk/android-testing-guide/fork) [![GitHub watchers](https://img.shields.io/github/watchers/ravidsrk/android-testing-guide.svg?style=social\u0026label=Watch)](https://github.com/ravidsrk/android-testing-guide) [![GitHub followers](https://img.shields.io/github/followers/ravidsrk.svg?style=social\u0026label=Follow)](https://github.com/ravidsrk/android-testing-guide) \n[![Twitter Follow](https://img.shields.io/twitter/follow/ravidsrk.svg?style=social)](https://twitter.com/ravidsrk)\n\n\u003e Complete reference for Android Testing with examples.\n\n## Contents\n\n- [Introduction](#introduction)\n    - [Why testing?](#why-testing)\n    - [Why unit test?](#why-unit-test)\n    - [Instrumented tests](#instrumented-tests)\n- [Local Tests](#local-tests)\n    - [JUnit basics](#junit-basics)\n    - [Beyond JUnit basics](#beyond-junit-basics)\n    - [Assertions](#assertions)\n    - [Hamcrest](#hamcrest)\n    - [Assertj](#assertj)\n    - [Rules](#rules)\n    - [Mockito](#mockito)\n    - [PowerMock](#powermock)\n    - [EasyMock](#easymock)\n    - [WireMock](#wiremock)\n    - [RESTMock](#restmock)\n- [Android](#android)\n    - [Android test rules](#android-test-rules)\n        - [Rule to test Android Activity](#rule-to-test-android-activity)\n        - [Rule to test Android Service](#rule-to-test-android-service)\n        - [Rule to test Android Intents](#rule-to-test-android-intents)\n    - [Android instrumented tests](#android-instrumented-tests)\n    - [Test filtering](#test-filtering)\n    - [Espresso](#espresso)\n        - [Basics](#basics)\n        - [Testing RecyclerView](#testing-recyclerview)\n        - [Testing Toast](#testing-toast)\n        - [Testing Intents](#testing-intents)\n        - [Testing Synchronization with background jobs](#idlingresource)\n    - [Robolectric](#robolectric)\n        - [Testing Activities](#testing-activities)\n        - [Testing Fragments](#testing-fragments)\n        - [Testing sqlite](#testing-sqlite)\n    - [Robotium](#robotium)\n    - [UI testing and UI Automator](#ui-testing-and-ui-automator)\n    - [MonkeyRunner](#monkeyrunner)\n- [References](#references)\n\n## Introduction\n\n### Why testing?\n\n* Testing forces you to think in a different way and implicitly makes your code cleaner in the process.\n* You feel more confident about your code if it has tests.\n* Shiny green status bars and cool reports detailing how much of your code is covered are both consequences of writing tests.\n* Regression testing is made a lot easier, as automated tests would pick up the bugs first.\n\n### Why unit test?\n\nA unit test generally exercises the functionality of the smallest possible unit of code (which could be a method, class, or component) in a repeatable way.\n\nTools that are used to do this testing:\n* [JUnit](http://junit.org/junit4/) – normal test assertions.\n* [Mockito](http://mockito.org/) – mocking out other classes that are not under test.\n* [PowerMock](https://github.com/jayway/powermock) – mocking out static classes such as Android Environment class etc.\n\n### Instrumented tests\n\nA UI Test or Instrumentation Test mocks typical user interactions with your app. Clicking on buttons, typing in text are some of the things UI Tests can complete.\n\n* [Espresso](https://google.github.io/android-testing-support-library/docs/espresso/) –  Used for testing within your app, selecting items, making sure something is visible.\n* [UIAutomator](https://developer.android.com/training/testing/ui-testing/uiautomator-testing.html) – Used for testing interaction between different apps.\n\nThere are other tools that are available for this kind of testing such as [Robotium](http://robotium.com/), [Appium](http://appium.io/), [Calabash](http://calaba.sh/), [Robolectric](http://robolectric.org/).\n\n## Local Tests\n\n### JUnit basics\n\n[Calculator.java](https://github.com/ravidsrk/android-testing-guide/blob/master/SampleApp/app/src/main/java/in/ravidsrk/sample/Calculator.java)\n\n```java\npublic class Calculator {\n\n    public int add(int op1, int op2) {\n        return op1 + op2;\n    }\n\n    public int diff(int op1, int op2) {\n        return op1 - op2;\n    }\n\n    public double div(int op1, int op2) {\n        // if (op2 == 0) return 0;\n        return op1 / op2;\n    }\n}\n```\n\n[CalculatorTest.java](https://github.com/ravidsrk/android-testing-guide/blob/master/SampleApp/app/src/test/java/in/ravidsrk/sample/CalculatorTest.java)\n\n```java\npublic class CalculatorTest {\n\n    private Calculator calculator;\n\n    @Before\n    public void setup() {\n        calculator = new Calculator();\n        System.out.println(\"Ready for testing!\");\n    }\n\n    @After\n    public void cleanup() {\n        System.out.println(\"Done with unit test!\");\n    }\n\n    @BeforeClass\n    public static void testClassSetup() {\n        System.out.println(\"Getting test class ready\");\n    }\n\n    @AfterClass\n    public static void testClassCleanup() {\n        System.out.println(\"Done with tests\");\n    }\n\n    @Test\n    public void testAdd() {\n        calculator = new Calculator();\n        int total = calculator.add(4, 5);\n        assertEquals(\"Calculator is not adding correctly\", 9, total);\n    }\n\n    @Test\n    public void testDiff() {\n        calculator = new Calculator();\n        int total = calculator.diff(9, 2);\n        assertEquals(\"Calculator is not subtracting correctly\", 7, total);\n    }\n\n    @Test\n    public void testDiv() {\n        calculator = new Calculator();\n        double total = calculator.div(9, 3);\n        assertEquals(\"Calculator is not dividing correctly\", 3.0, total, 0.0);\n    }\n}\n\n```\n\n### Beyond JUnit basics\n\n[CalculatorTest.java](https://github.com/ravidsrk/android-testing-guide/blob/master/SampleApp/app/src/test/java/in/ravidsrk/sample/CalculatorTest.java#L62)\n\n```java\n@Ignore\n@Test(expected = java.lang.ArithmeticException.class)\npublic void testDivWithZeroDivisor() {\n    calculator = new Calculator();\n    double total = calculator.div(9, 0);\n    assertEquals(\"Calculator is not handling division by zero correctly\", 0.0, total, 0.0);\n}\n```\n\n### Assertions\n\nJUnit provides overloaded assertion methods for all primitive types and Objects and arrays (of primitives or Objects). The parameter order is expected value followed by actual value. Optionally the first parameter can be a String message that is output on failure. There is a slightly different assertion, assertThat that has parameters of the optional failure message, the actual value, and a Matcher object. Note that expected and actual are reversed compared to the other assert methods.\n\n[AssertTests.java](https://github.com/ravidsrk/android-testing-guide/blob/master/SampleApp/app/src/test/java/in/ravidsrk/sample/AssertTests.java)\n\n```java\npublic class AssertTests {\n  @Test\n  public void testAssertArrayEquals() {\n    byte[] expected = \"trial\".getBytes();\n    byte[] actual = \"trial\".getBytes();\n    assertArrayEquals(\"failure - byte arrays not same\", expected, actual);\n  }\n\n  @Test\n  public void testAssertEquals() {\n    assertEquals(\"failure - strings are not equal\", \"text\", \"text\");\n  }\n\n  @Test\n  public void testAssertFalse() {\n    assertFalse(\"failure - should be false\", false);\n  }\n\n  @Test\n  public void testAssertNotNull() {\n    assertNotNull(\"should not be null\", new Object());\n  }\n\n  @Test\n  public void testAssertNotSame() {\n    assertNotSame(\"should not be same Object\", new Object(), new Object());\n  }\n\n  @Test\n  public void testAssertNull() {\n    assertNull(\"should be null\", null);\n  }\n\n  @Test\n  public void testAssertSame() {\n    Integer aNumber = Integer.valueOf(768);\n    assertSame(\"should be same\", aNumber, aNumber);\n  }\n\n  // JUnit Matchers assertThat\n  @Test\n  public void testAssertThatBothContainsString() {\n    assertThat(\"albumen\", both(containsString(\"a\")).and(containsString(\"b\")));\n  }\n\n  @Test\n  public void testAssertThatHasItems() {\n    assertThat(Arrays.asList(\"one\", \"two\", \"three\"), hasItems(\"one\", \"three\"));\n  }\n\n  @Test\n  public void testAssertThatEveryItemContainsString() {\n    assertThat(Arrays.asList(new String[] { \"fun\", \"ban\", \"net\" }), everyItem(containsString(\"n\")));\n  }\n\n  // Core Hamcrest Matchers with assertThat\n  @Test\n  public void testAssertThatHamcrestCoreMatchers() {\n    assertThat(\"good\", allOf(equalTo(\"good\"), startsWith(\"good\")));\n    assertThat(\"good\", not(allOf(equalTo(\"bad\"), equalTo(\"good\"))));\n    assertThat(\"good\", anyOf(equalTo(\"bad\"), equalTo(\"good\")));\n    assertThat(7, not(CombinableMatcher.\u003cInteger\u003e either(equalTo(3)).or(equalTo(4))));\n    assertThat(new Object(), not(sameInstance(new Object())));\n  }\n\n  @Test\n  public void testAssertTrue() {\n    assertTrue(\"failure - should be true\", true);\n  }\n}\n```\n\n### Hamcrest\n\n[HamcrestTest.java](https://github.com/ravidsrk/android-testing-guide/blob/master/SampleApp/app/src/test/java/in/ravidsrk/sample/HamcrestTest.java)\n\n```java\npublic class HamcrestTest {\n\n    @Test\n    public void testWithAsserts() {\n        List\u003cString\u003e list = generateStingList();\n        assertTrue(list.contains(\"android\"));\n        assertTrue(list.contains(\"context\"));\n        assertTrue(list.size() \u003e 4);\n        assertTrue(list.size() \u003c 13);\n    }\n\n    @Test\n    public void testWithBigAssert() {\n        List\u003cString\u003e list = generateStingList();\n        assertTrue(list.contains(\"android\") \u0026\u0026 list.contains(\"context\") \u0026\u0026 list.size() \u003e 3 \u0026\u0026 list.size() \u003c 12);\n    }\n\n    @Test\n    public void testWithHamcrest() {\n        List\u003cString\u003e list = generateStingList();\n        assertThat(list, (hasItems(\"android\", \"context\")));\n        assertThat(list, allOf(hasSize(greaterThan(3)), hasSize(lessThan(12))));\n    }\n\n    @Test\n    public void testFailureWithAsserts() {\n        List\u003cString\u003e list = generateStingList();\n        assertTrue(list.contains(\"android\"));\n        assertTrue(list.contains(\"service\"));\n        assertTrue(list.size() \u003e 3);\n        assertTrue(list.size() \u003c 12);\n    }\n\n    @Test\n    public void testFailureWithHamcrest() {\n        List\u003cString\u003e list = generateStingList();\n        assertThat(list, (hasItems(\"android\", \"service\")));\n        assertThat(list, allOf(hasSize(greaterThan(3)), hasSize(lessThan(12))));\n    }\n\n    @Test\n    public void testTypeSafety() {\n        // assertThat(\"123\", equalTo(123));\n        // assertThat(123, equalTo(\"123\"));\n    }\n\n    private List\u003cString\u003e generateStingList() {\n        String[] sentence = {\"android\", \"context\", \"service\", \"manifest\", \"layout\", \"resource\", \"broadcast\", \"receiver\", \"gradle\"};\n        return Arrays.asList(sentence);\n    }\n}\n```\n\n### Rules\n\n[CalculatorWithTestName.java](https://github.com/ravidsrk/android-testing-guide/blob/master/SampleApp/app/src/test/java/in/ravidsrk/sample/CalculatorWithTestName.java)\n\n```java\npublic class CalculatorWithTestName {\n\n    @Rule\n    public TestName name = new TestName();\n\n    @Test\n    public void testAdd() {\n        Calculator calculator = new Calculator();\n        int total = calculator.add(4, 5);\n        assertEquals(name.getMethodName() + \" adding incorrectly\", 9, total);\n    }\n\n    @Test\n    public void testDiff() {\n        Calculator calculator = new Calculator();\n        int total = calculator.diff(12, 7);\n        assertEquals(name.getMethodName() + \" subtracting incorrectly\", 5, total);\n    }\n}\n```\n\n## RESTMock\n\nRESTMock is a library working on top of Square's [okhttp/MockWebServer](https://github.com/square/okhttp/tree/master/mockwebserver). It allows you to specify [Hamcrest](https://github.com/hamcrest/JavaHamcrest) matchers to match HTTP requests and specify what response to return. It is as easy as:\n\n```java\nRESTMockServer.whenGET(pathContains(\"users/defunkt\"))\n            .thenReturnFile(200, \"users/defunkt.json\");\n```\n\n#### Step 1: Start the server\nIt's good to start server before the tested application starts, there are few methods:\n\n##### a) RESTMockTestRunner\nTo make it simple you can just use the predefined `RESTMockTestRunner` in your UI tests. It extends `AndroidJUnitRunner`:\n\n```groovy\ndefaultConfig {\n        ...\n        testInstrumentationRunner 'io.appflate.restmock.android.RESTMockTestRunner'\n    }\n```\n##### b) RESTMockServerStarter\nIf you have your custom test runner and you can't extend `RESTMockTestRunner`, you can always just call the `RESTMockServerStarter`. Actually `RESTMockTestRunner` is doing exactly the same thing:\n\n```java\npublic class MyAppTestRunner extends AndroidJUnitRunner {\n    ...\n    @Override\n    public void onCreate(Bundle arguments) {\n        super.onCreate(arguments);\n        RESTMockServerStarter.startSync(new AndroidAssetsFileParser(getContext()),new AndroidLogger());\n        ...\n    }\n    ...\n}\n\n```\n\n\n#### Step 2: Specify Mocks\n\n##### a) Files\nBy default, the `RESTMockTestRunner` uses `AndroidAssetsFileParser` as a mocks file parser, which reads the files from the assets folder. To make them visible for the RESTMock you have to put them in the correct folder in your project, for example:\n\n    .../src/androidTest/assets/users/defunkt.json\nThis can be accessed like this:\n\n```java\nRESTMockServer.whenGET(pathContains(\"users/defunkt\"))\n            .thenReturnFile(200, \"users/defunkt.json\");\n```\n\n##### b) Strings\nIf the response You wish to return is simple, you can just specify a string:\n\n```java\nRESTMockServer.whenGET(pathContains(\"users/defunkt\"))\n            .thenReturnString(200, \"{}\");\n```\n##### c) MockResponse\nIf you wish to have a greater control over the response, you can pass the `MockResponse`\n```java\nRESTMockServer.whenGET(pathContains(\"users/defunkt\")).thenReturn(new MockResponse().setBody(\"\").setResponseCode(401).addHeader(\"Header\",\"Value\"));\n```\n\n#### Step 3: Request Matchers\nYou can either use some of the predefined matchers from `RequestMatchers` util class, or create your own. remember to extend from `RequestMatcher`\n\n#### Step 4: Specify API Endpoint\nThe most important step, in order for your app to communicate with the testServer, you have to specify it as an endpoint for all your API calls. For that, you can use the ` RESTMockServer.getUrl()`. If you use Retrofit, it is as easy as:\n\n```java\nRestAdapter adapter = new RestAdapter.Builder()\n                .baseUrl(RESTMockServer.getUrl())\n                ...\n                .build();\n```\n#### Request verification\nIt is possible to verify which requests were called and how many times thanks to `RequestsVerifier`. All you have to do is call one of these:\n\n```java\n//cheks if the GET request was invoked exactly 2 times\nRequestsVerifier.verifyGET(pathEndsWith(\"users\")).exactly(2);\n\n//cheks if the GET request was invoked at least 3 times\nRequestsVerifier.verifyGET(pathEndsWith(\"users\")).atLeast(3);\n\n//cheks if the GET request was invoked exactly 1 time\nRequestsVerifier.verifyGET(pathEndsWith(\"users\")).invoked();\n\n//cheks if the GET request was never invoked\nRequestsVerifier.verifyGET(pathEndsWith(\"users\")).never();\n```\n\n#### Logging\nRESTMock supports logging events. You just have to provide the RESTMock with the implementation of `RESTMockLogger`. For Android there is an `AndroidLogger` implemented already. All you have to do is use the `RESTMockTestRunner` or call\n\n```java\nRESTMockServerStarter.startSync(new AndroidAssetsFileParser(getContext()),new AndroidLogger());\n```\n\nor\n\n```java\nRESTMockServer.enableLogging(RESTMockLogger)\nRESTMockServer.disableLogging()\n```\n\n## Android\n\n### Android test rules\n\n#### Rule to test Android Activity\n\n[MainActivityTestRule.java](https://github.com/ravidsrk/android-testing-guide/blob/master/SampleApp/app/src/androidTest/java/in/ravidsrk/sample/MainActivityTestRule.java)\n\n```java\npublic class MainActivityTestRule\u003cA extends Activity\u003e extends ActivityTestRule\u003cA\u003e {\n\n    public MainActivityTestRule(Class\u003cA\u003e activityClass) {\n        super(activityClass);\n    }\n    @Override\n    protected Intent getActivityIntent() {\n        Log.e(\"MainActivityTestRule\", \"Prepare the activity's intent\");\n        return super.getActivityIntent();\n    }\n\n    @Override\n    protected void beforeActivityLaunched() {\n        Log.e(\"MainActivityTestRule\", \"Execute before the activity is launched\");\n        super.beforeActivityLaunched();\n    }\n\n    @Override\n    protected void afterActivityLaunched() {\n        Log.e(\"MainActivityTestRule\", \"Execute after the activity has been launched\");\n        super.afterActivityLaunched();\n    }\n\n    @Override\n    protected void afterActivityFinished() {\n        Log.e(\"MainActivityTestRule\", \"Cleanup after it has finished\");\n        super.afterActivityFinished();\n    }\n\n    @Override\n    public A launchActivity(Intent startIntent) {\n        Log.e(\"MainActivityTestRule\", \"Launching the activity\");\n        return super.launchActivity(startIntent);\n    }\n}\n```\n\n#### Rule to test Android Service\n\n[SampleServiceTestRule.java](https://github.com/ravidsrk/android-testing-guide/blob/master/SampleApp/app/src/androidTest/java/in/ravidsrk/sample/SampleServiceTest.java)\n\n```java\npublic class SampleServiceTestRule extends ServiceTestRule {\n\n    @Override\n    public void startService(Intent intent) throws TimeoutException {\n        Log.e(\"SampleServiceTestRule\", \"start the service\");\n        super.startService(intent);\n    }\n\n    @Override\n    public IBinder bindService(Intent intent) throws TimeoutException {\n        Log.e(\"SampleServiceTestRule\", \"binding the service\");\n        return super.bindService(intent);\n    }\n\n    @Override\n    protected void beforeService() {\n        Log.e(\"SampleServiceTestRule\", \"work before the service starts\");\n        super.beforeService();\n    }\n\n    @Override\n    protected void afterService() {\n        Log.e(\"SampleServiceTestRule\", \"work after the service has started\");\n        super.afterService();\n    }\n}\n```\n\n### Android instrumented tests\n#### Testing Android Activity\n\n[MainActivityTest.java](https://github.com/ravidsrk/android-testing-guide/blob/master/SampleApp/app/src/androidTest/java/in/ravidsrk/sample/MainActivityTest.java)\n\n```java\n@RunWith(AndroidJUnit4.class)\npublic class MainActivityTest {\n\n    @Rule\n    public MainActivityTestRule\u003cMainActivity\u003e mainActivityActivityTestRule = new MainActivityTestRule\u003cMainActivity\u003e(MainActivity.class);\n\n    @Test\n    public void testUI() {\n        Activity activity = mainActivityActivityTestRule.getActivity();\n        assertNotNull(activity.findViewById(R.id.text_hello));\n        TextView helloView = (TextView) activity.findViewById(R.id.text_hello);\n        assertTrue(helloView.isShown());\n        assertEquals(\"Hello World!\", helloView.getText());\n        assertEquals(InstrumentationRegistry.getTargetContext().getString(R.string.hello_world), helloView.getText());\n        assertNull(activity.findViewById(android.R.id.button1));\n    }\n}\n```\n\n#### Testing Android Service\n\n[SampleServiceTest](https://github.com/ravidsrk/android-testing-guide/blob/master/SampleApp/app/src/androidTest/java/in/ravidsrk/sample/SampleServiceTest.java)\n\n```java\n@RunWith(AndroidJUnit4.class)\npublic class SampleServiceTest {\n\n    @Rule\n    public SampleServiceTestRule myServiceRule = new SampleServiceTestRule();\n\n    @Test\n    public void testService() throws TimeoutException {\n        myServiceRule.startService(new Intent(InstrumentationRegistry.getTargetContext(), SampleService.class));\n    }\n\n    @Test\n    public void testBoundService() throws TimeoutException {\n        IBinder binder = myServiceRule.bindService(\n                new Intent(InstrumentationRegistry.getTargetContext(), SampleService.class));\n        SampleService service = ((SampleService.LocalBinder) binder).getService();\n        // Do work with the service\n        assertNotNull(\"Bound service is null\", service);\n    }\n}\n```\n\n### Test filtering\n\n[MainActivityTest.java](https://github.com/ravidsrk/android-testing-guide/blob/master/SampleApp/app/src/androidTest/java/in/ravidsrk/sample/MainActivityTest.java#L61)\n\n```java\n@Test\n@RequiresDevice\npublic void testRequiresDevice() {\n    Log.d(\"Test Filters\", \"This test requires a device\");\n    Activity activity = activityTestRule.getActivity();\n    assertNotNull(\"MainActivity is not available\", activity);\n}\n\n@Test\n@SdkSuppress(minSdkVersion = 30)\npublic void testMinSdkVersion() {\n    Log.d(\"Test Filters\", \"Checking for min sdk \u003e= 30\");\n    Activity activity = activityTestRule.getActivity();\n    assertNotNull(\"MainActivity is not available\", activity);\n}\n\n@Test\n@SdkSuppress(minSdkVersion = Build.VERSION_CODES.LOLLIPOP)\npublic void testMinBuild() {\n    Log.d(\"Test Filters\", \"Checking for min build \u003e Lollipop\");\n    Activity activity = activityTestRule.getActivity();\n    assertNotNull(\"MainActivity is not available\", activity);\n}\n\n@Test\n@SmallTest\npublic void testSmallTest() {\n    Log.d(\"Test Filters\", \"this is a small test\");\n    Activity activity = activityTestRule.getActivity();\n    assertNotNull(\"MainActivity is not available\", activity);\n}\n\n@Test\n@LargeTest\npublic void testLargeTest() {\n    Log.d(\"Test Filters\", \"This is a large test\");\n    Activity activity = activityTestRule.getActivity();\n    assertNotNull(\"MainActivity is not available\", activity);\n}\n```\n\n### Espresso\n\n[MainActivityTest.java](https://github.com/ravidsrk/android-testing-guide/blob/master/SampleApp/app/src/androidTest/java/in/ravidsrk/sample/MainActivityTest.java#L134)\n\n```java\n@Test\npublic void testEspresso() {\n    ViewInteraction interaction =\n            onView(allOf(withId(R.id.editText),\n                    withText(\"this is a test\"),\n                    hasFocus()));\n    interaction.perform(replaceText(\"how about some new text\"));\n    ViewInteraction interaction2 =\n            onView(allOf(withId(R.id.editText),\n                    withText(\"how about some new text\")));\n    interaction2.check(matches(hasFocus()));\n}\n\n@Test\npublic void testEspressoSimplified() {\n    onView(allOf(withId(R.id.editText),\n            withText(\"this is a test\"),\n            hasFocus())).perform(replaceText(\"how about some new text\"));\n    onView(allOf(withId(R.id.editText),\n            withText(\"how about some new text\"))).check(matches(hasFocus()));\n}\n\n```\n\n### Robolectric\n\n[MainActivityRoboelectricTest.java](https://github.com/ravidsrk/android-testing-guide/blob/master/SampleApp/app/src/test/java/in/ravidsrk/sample/MainActivityRoboelectricTest.java)\n\n```java\n@RunWith(RobolectricGradleTestRunner.class)\n@Config(constants = BuildConfig.class)\npublic class MainActivityRoboelectricTest {\n\n    private MainActivity activity;\n\n    @Before\n    public void setup() {\n        activity = Robolectric.setupActivity(MainActivity.class);\n    }\n\n    @Test\n    public void clickButton() {\n        Button button = (Button) activity.findViewById(R.id.button);\n        assertNotNull(\"test button could not be found\", button);\n        assertTrue(\"button does not contain text 'Click Me!'\", \"Click Me\".equals(button.getText()));\n    }\n\n}\n```\n\n### Robotium\n\n[MainActivityRobotiumTest.java](https://github.com/ravidsrk/android-testing-guide/blob/master/SampleApp/app/src/androidTest/java/in/ravidsrk/sample/MainActivityRobotiumTest.java)\n\n```java\npublic class MainActivityRobotiumTest {\n    private Solo solo;\n\n    @Rule\n    public ActivityTestRule\u003cMainActivity\u003e activityTestRule =\n            new ActivityTestRule\u003c\u003e(MainActivity.class);\n\n    public void setUp() {\n        solo = new Solo(InstrumentationRegistry.getInstrumentation(),\n                activityTestRule.getActivity());\n    }\n\n    public void tearDown() {\n        solo.finishOpenedActivities();\n    }\n\n    @Test\n    public void testPushClickMe() {\n        solo.waitForActivity(MainActivity.class);\n        solo.assertCurrentActivity(\"MainActivity is not displayed\", MainActivity.class);\n        assertTrue(\"This is a test in EditText is not displayed\",\n                solo.searchText(\"this is a test\"));\n        solo.clickOnButton(\"Click Me\");\n        assertTrue(\"You clicked me text is not displayed in the EditText\",\n                solo.searchText(\"you clicked me!\"));\n    }\n}\n```\n\n### UI testing and UI Automator\n\n[MainActivityTest](https://github.com/ravidsrk/android-testing-guide/blob/master/SampleApp/app/src/androidTest/java/in/ravidsrk/sample/MainActivityTest.java#L101)\n\n```java\n@Test\npublic void testPressBackButton() {\n    UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()).pressBack();\n}\n\n@Test\n@Ignore\npublic void testUiDevice() throws RemoteException {\n    UiDevice device = UiDevice.getInstance(\n            InstrumentationRegistry.getInstrumentation());\n    if (device.isScreenOn()) {\n        device.setOrientationLeft();\n        device.openNotification();\n    }\n}\n\n@Test\npublic void testUiAutomatorAPI() throws UiObjectNotFoundException, InterruptedException {\n    UiDevice device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());\n\n    UiSelector editTextSelector = new UiSelector().className(\"android.widget.EditText\").text(\"this is a test\").focusable(true);\n    UiObject editTextWidget = device.findObject(editTextSelector);\n    editTextWidget.setText(\"this is new text\");\n\n    Thread.sleep(2000);\n\n    UiSelector buttonSelector = new UiSelector().className(\"android.widget.Button\").text(\"Click Me\").clickable(true);\n    UiObject buttonWidget = device.findObject(buttonSelector);\n    buttonWidget.click();\n\n    Thread.sleep(2000);\n\n}\n```\n\n### MonkeyRunner\n\n[sampletest.py](https://github.com/ravidsrk/android-testing-guide/blob/master/SampleApp/sampletest.py)\n\n```python\n# Imports the monkeyrunner modules\nfrom com.android.monkeyrunner import MonkeyRunner, MonkeyDevice, MonkeyImage\n\n# Alert the user a MonkeyRunner script is about to execute\nMonkeyRunner.alert(\"Monkeyrunner about to execute\",\"Monkeyrunner\",\"OK\")\n\n# Connects to the current emulator\nemulator= MonkeyRunner.waitForConnection()\n\n# Install the Android app package and test package\nemulator.installPackage('./app/build/outputs/apk/app-debug-unaligned.apk')\nemulator.installPackage('./app/build/outputs/apk/app-debug-androidTest-unaligned.apk')\n\n# sets a variable with the package's internal name\npackage = 'in.ravidsrk.sample'\n\n# sets a variable with the name of an Activity in the package\nactivity = 'in.ravidsrk.sample.MainActivity'\n\n# sets the name of the component to start\nrunComponent = package + '/' + activity\n\n# Runs the component\nemulator.startActivity(runComponent)\n\n# wait for the screen to fully come up\nMonkeyRunner.sleep(2.0)\n\n# Takes a screenshot\nsnapshot = emulator.takeSnapshot()\n\n# Writes the screenshot to a file\nsnapshot.writeToFile('mainactivity.png','png')\n\n# Alert the user a testing is about to be run by MonkeyRunner\nMonkeyRunner.alert(\"Instrumented test about to execute\",\"Monkeyrunner\",\"OK\")\n\n#kick off the instrumented test\nemulator.shell('am instrument -w in.ravidsrk.sample.test/android.support.test.runner.AndroidJUnitRunner')\n\n# return to the emulator home screen\nemulator.press('KEYCODE_HOME','DOWN_AND_UP')\n\n```\n\n## References\n* \u003chttps://github.com/junit-team/junit4/wiki/assertions\u003e\n* \u003chttps://github.com/googlesamples/android-testing\u003e\n* \u003chttps://riggaroo.co.za/introduction-automated-android-testing/\u003e\n* \u003chttp://robolectric.org\u003e\n* \u003chttps://github.com/robolectric/robolectric\u003e\n* \u003chttps://www.bignerdranch.com/blog/triumph-android-studio-1-2-sneaks-in-full-testing-support\u003e\n* \u003chttps://github.com/mutexkid/android-studio-robolectric-example\u003e\n* \u003chttp://blog.nikhaldimann.com/2013/10/10/robolectric-2-2-some-pages-from-the-missing-manual\u003e\n* \u003chttps://corner.squareup.com/2013/04/the-resurrection-of-testing-for-android.html\u003e\n* \u003chttp://simpleprogrammer.com/2010/07/27/the-best-way-to-unit-test-in-android/\u003e\n* \u003chttps://youtu.be/f7ihSQ44WO0?t=15m11s\u003e\n* \u003chttps://code.google.com/p/android-test-kit\u003e\n* \u003chttps://developer.android.com/training/testing/ui-testing/espresso-testing.html\u003e\n* \u003chttps://github.com/vgrec/EspressoExamples\u003e\n* \u003chttps://github.com/designatednerd/Wino\u003e\n* \u003chttp://chiuki.github.io/advanced-android-espresso/#/\u003e\n* \u003chttp://www.vogella.com/tutorials/AndroidTestingEspresso/article.html\u003e\n\n## Contributors\n\nThis project exists thanks to all the people who contribute.\n\u003ca href=\"graphs/contributors\"\u003e\u003cimg src=\"https://opencollective.com/android-testing-guide/contributors.svg?width=890\" /\u003e\u003c/a\u003e\n\n\n## Backers\n\nThank you to all our backers! 🙏 [[Become a backer](https://opencollective.com/android-testing-guide#backer)]\n\n\u003ca href=\"https://opencollective.com/android-testing-guide#backers\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/android-testing-guide/backers.svg?width=890\"\u003e\u003c/a\u003e\n\n\n## Sponsors\n\nSupport this project by becoming a sponsor. Your logo will show up here with a link to your website. [[Become a sponsor](https://opencollective.com/android-testing-guide#sponsor)]\n\n\u003ca href=\"https://opencollective.com/android-testing-guide/sponsor/0/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/android-testing-guide/sponsor/0/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/android-testing-guide/sponsor/1/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/android-testing-guide/sponsor/1/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/android-testing-guide/sponsor/2/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/android-testing-guide/sponsor/2/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/android-testing-guide/sponsor/3/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/android-testing-guide/sponsor/3/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/android-testing-guide/sponsor/4/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/android-testing-guide/sponsor/4/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/android-testing-guide/sponsor/5/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/android-testing-guide/sponsor/5/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/android-testing-guide/sponsor/6/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/android-testing-guide/sponsor/6/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/android-testing-guide/sponsor/7/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/android-testing-guide/sponsor/7/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/android-testing-guide/sponsor/8/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/android-testing-guide/sponsor/8/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/android-testing-guide/sponsor/9/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/android-testing-guide/sponsor/9/avatar.svg\"\u003e\u003c/a\u003e\n\n\n","funding_links":["https://opencollective.com/android-testing-guide"],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fravidsrk%2Fandroid-testing-guide","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fravidsrk%2Fandroid-testing-guide","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fravidsrk%2Fandroid-testing-guide/lists"}