xref: /aosp_15_r20/external/mobly-snippet-lib/examples/ex2_espresso/README.md (revision ae5b1ec8a57d9cd6259556f14d3f2bb4f9fb3a85)
1*ae5b1ec8SZiwei Zhang# Espresso Snippet Example
2*ae5b1ec8SZiwei Zhang
3*ae5b1ec8SZiwei ZhangThis tutorial shows you how to create snippets that automate the UI of another
4*ae5b1ec8SZiwei Zhangapp using Espresso.
5*ae5b1ec8SZiwei Zhang
6*ae5b1ec8SZiwei ZhangThe same approach can be used to create any snippet app that needs to access
7*ae5b1ec8SZiwei Zhangthe classes or resources of any other single app.
8*ae5b1ec8SZiwei Zhang
9*ae5b1ec8SZiwei Zhang## Overview
10*ae5b1ec8SZiwei Zhang
11*ae5b1ec8SZiwei ZhangTo build a snippet that instruments another app, you have to create a new
12*ae5b1ec8SZiwei Zhang[product flavor](https://developer.android.com/studio/build/build-variants.html#product-flavors)
13*ae5b1ec8SZiwei Zhangof your existing app with the snippet code built in.
14*ae5b1ec8SZiwei Zhang
15*ae5b1ec8SZiwei ZhangThe snippet code cannot run from a regular test apk because it requires a custom
16*ae5b1ec8SZiwei Zhang`testInstrumentationRunner`.
17*ae5b1ec8SZiwei Zhang
18*ae5b1ec8SZiwei Zhang## Tutorial
19*ae5b1ec8SZiwei Zhang
20*ae5b1ec8SZiwei Zhang1.  In the `build.gradle` file of your existing app, create a new product flavor called `snippet`.
21*ae5b1ec8SZiwei Zhang
22*ae5b1ec8SZiwei Zhang    ```
23*ae5b1ec8SZiwei Zhang    android {
24*ae5b1ec8SZiwei Zhang      defaultConfig { ... }
25*ae5b1ec8SZiwei Zhang      productFlavors {
26*ae5b1ec8SZiwei Zhang        main {}
27*ae5b1ec8SZiwei Zhang        snippet {}
28*ae5b1ec8SZiwei Zhang      }
29*ae5b1ec8SZiwei Zhang    }
30*ae5b1ec8SZiwei Zhang    ```
31*ae5b1ec8SZiwei Zhang
32*ae5b1ec8SZiwei Zhang1.  Link against Mobly Snippet Lib in your `build.gradle` file
33*ae5b1ec8SZiwei Zhang
34*ae5b1ec8SZiwei Zhang    ```
35*ae5b1ec8SZiwei Zhang    dependencies {
36*ae5b1ec8SZiwei Zhang      snippetCompile 'com.google.android.mobly:mobly-snippet-lib:1.4.0'
37*ae5b1ec8SZiwei Zhang    }
38*ae5b1ec8SZiwei Zhang    ```
39*ae5b1ec8SZiwei Zhang
40*ae5b1ec8SZiwei Zhang1.  Create a new source tree called `src/snippet` where you will place the
41*ae5b1ec8SZiwei Zhang    snippet code.
42*ae5b1ec8SZiwei Zhang
43*ae5b1ec8SZiwei Zhang1.  In Android Studio, use the `Build Variants` tab in the left hand pane to
44*ae5b1ec8SZiwei Zhang    switch to the snippetDebug build variant. This will let you edit code in the
45*ae5b1ec8SZiwei Zhang    new tree.
46*ae5b1ec8SZiwei Zhang
47*ae5b1ec8SZiwei Zhang1.  Write your snippet code in a new class under `src/snippet/java`
48*ae5b1ec8SZiwei Zhang
49*ae5b1ec8SZiwei Zhang    ```java
50*ae5b1ec8SZiwei Zhang    package com.my.app;
51*ae5b1ec8SZiwei Zhang    ...
52*ae5b1ec8SZiwei Zhang    public class EspressoSnippet implements Snippet {
53*ae5b1ec8SZiwei Zhang      @Rpc(description="Pushes the main app button.")
54*ae5b1ec8SZiwei Zhang      public void pushMainButton() {
55*ae5b1ec8SZiwei Zhang        onView(withId(R.id.main_button)).perform(click());
56*ae5b1ec8SZiwei Zhang      }
57*ae5b1ec8SZiwei Zhang
58*ae5b1ec8SZiwei Zhang      @Override
59*ae5b1ec8SZiwei Zhang      public void shutdown() {}
60*ae5b1ec8SZiwei Zhang    }
61*ae5b1ec8SZiwei Zhang    ```
62*ae5b1ec8SZiwei Zhang
63*ae5b1ec8SZiwei Zhang1.  Create `src/snippet/AndroidManifest.xml` containing an `<instrument>` block
64*ae5b1ec8SZiwei Zhang    and any classes that implement the `Snippet` interface in `meta-data`
65*ae5b1ec8SZiwei Zhang
66*ae5b1ec8SZiwei Zhang    ```xml
67*ae5b1ec8SZiwei Zhang    <?xml version="1.0" encoding="utf-8"?>
68*ae5b1ec8SZiwei Zhang    <manifest xmlns:android="http://schemas.android.com/apk/res/android">
69*ae5b1ec8SZiwei Zhang      <application>
70*ae5b1ec8SZiwei Zhang        <meta-data
71*ae5b1ec8SZiwei Zhang          android:name="mobly-snippets"
72*ae5b1ec8SZiwei Zhang          android:value="com.my.app.EspressoSnippet" />
73*ae5b1ec8SZiwei Zhang      </application>
74*ae5b1ec8SZiwei Zhang
75*ae5b1ec8SZiwei Zhang      <instrumentation
76*ae5b1ec8SZiwei Zhang        android:name="com.google.android.mobly.snippet.SnippetRunner"
77*ae5b1ec8SZiwei Zhang        android:targetPackage="com.my.app" />
78*ae5b1ec8SZiwei Zhang    </manifest>
79*ae5b1ec8SZiwei Zhang    ```
80*ae5b1ec8SZiwei Zhang
81*ae5b1ec8SZiwei Zhang1.  Build your apk by invoking the new `assembleSnippetDebug` target.
82*ae5b1ec8SZiwei Zhang
83*ae5b1ec8SZiwei Zhang1.  Install the apk on your phone. You do not need to install the main app's
84*ae5b1ec8SZiwei Zhang    apk; the snippet-enabled apk is a complete replacement for your app.
85*ae5b1ec8SZiwei Zhang
86*ae5b1ec8SZiwei Zhang1.  In your Mobly python test, connect to your snippet .apk in `setup_class`
87*ae5b1ec8SZiwei Zhang
88*ae5b1ec8SZiwei Zhang    ```python
89*ae5b1ec8SZiwei Zhang    class HelloWorldTest(base_test.BaseTestClass):
90*ae5b1ec8SZiwei Zhang      def setup_class(self):
91*ae5b1ec8SZiwei Zhang        self.ads = self.register_controller(android_device)
92*ae5b1ec8SZiwei Zhang        self.dut1 = self.ads[0]
93*ae5b1ec8SZiwei Zhang        self.dut1.load_snippet(name='snippet', package='com.my.app')
94*ae5b1ec8SZiwei Zhang    ```
95*ae5b1ec8SZiwei Zhang
96*ae5b1ec8SZiwei Zhang6.  Invoke your needed functionality within your test
97*ae5b1ec8SZiwei Zhang
98*ae5b1ec8SZiwei Zhang    ```python
99*ae5b1ec8SZiwei Zhang    def test_click_button(self):
100*ae5b1ec8SZiwei Zhang      self.dut1.snippet.pushMainButton()
101*ae5b1ec8SZiwei Zhang    ```
102*ae5b1ec8SZiwei Zhang
103*ae5b1ec8SZiwei Zhang## Running the example code
104*ae5b1ec8SZiwei Zhang
105*ae5b1ec8SZiwei ZhangThis folder contains a fully working example of a snippet apk that uses espresso
106*ae5b1ec8SZiwei Zhangto automate a simple app.
107*ae5b1ec8SZiwei Zhang
108*ae5b1ec8SZiwei Zhang1.  Compile the example
109*ae5b1ec8SZiwei Zhang
110*ae5b1ec8SZiwei Zhang        ./gradlew examples:ex2_espresso:assembleSnippetDebug
111*ae5b1ec8SZiwei Zhang
112*ae5b1ec8SZiwei Zhang1.  Install the apk on your phone
113*ae5b1ec8SZiwei Zhang
114*ae5b1ec8SZiwei Zhang        adb install -r ./examples/ex2_espresso/build/outputs/apk/snippet/debug/ex2_espresso-snippet-debug.apk
115*ae5b1ec8SZiwei Zhang
116*ae5b1ec8SZiwei Zhang1.  Use `snippet_shell` from mobly to trigger `pushMainButton()`:
117*ae5b1ec8SZiwei Zhang
118*ae5b1ec8SZiwei Zhang        snippet_shell.py com.google.android.mobly.snippet.example2
119*ae5b1ec8SZiwei Zhang
120*ae5b1ec8SZiwei Zhang        >>> print(s.help())
121*ae5b1ec8SZiwei Zhang        Known methods:
122*ae5b1ec8SZiwei Zhang          pushMainButton(boolean) returns void  // Pushes the main app button, and checks the label if this is the first time.
123*ae5b1ec8SZiwei Zhang          startMainActivity() returns void  // Opens the main activity of the app
124*ae5b1ec8SZiwei Zhang
125*ae5b1ec8SZiwei Zhang        >>> s.startMainActivity()
126*ae5b1ec8SZiwei Zhang        >>> s.pushMainButton(True)
127*ae5b1ec8SZiwei Zhang
128*ae5b1ec8SZiwei Zhang1. Press ctrl+d to exit the shell and terminate the app.
129