<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Ryan</title>
    <description>The latest articles on DEV Community by Ryan (@ryansgot).</description>
    <link>https://dev.to/ryansgot</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F108381%2F5c8dab7c-38be-4496-bb80-58df4be083b6.gif</url>
      <title>DEV Community: Ryan</title>
      <link>https://dev.to/ryansgot</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ryansgot"/>
    <language>en</language>
    <item>
      <title>Testing Activity lifecycle callback methods in Android</title>
      <dc:creator>Ryan</dc:creator>
      <pubDate>Sun, 12 Jan 2020 17:27:29 +0000</pubDate>
      <link>https://dev.to/ryansgot/testing-activity-lifecycle-callback-methods-in-android-3d7j</link>
      <guid>https://dev.to/ryansgot/testing-activity-lifecycle-callback-methods-in-android-3d7j</guid>
      <description>&lt;p&gt;Suppose that you're testing an &lt;code&gt;Activity&lt;/code&gt; class. In this &lt;code&gt;Activity&lt;/code&gt; class, the &lt;code&gt;Intent&lt;/code&gt; used to start the &lt;code&gt;Activity&lt;/code&gt; causes a difference in behavior in the &lt;code&gt;onCreate()&lt;/code&gt;, &lt;code&gt;onStart()&lt;/code&gt; or &lt;code&gt;onResume()&lt;/code&gt; lifecycle callbacks. Therefore, you need to test that the &lt;code&gt;Activity&lt;/code&gt; class treats different &lt;code&gt;Intent&lt;/code&gt; instances differently. This is straightforward enough, right? Just create a different &lt;code&gt;Intent&lt;/code&gt; for a bunch of different variations of the test . . . but how do you do that?&lt;/p&gt;

&lt;p&gt;As a simple example that illustrates the true problem in setting up the test and motivates the solution, we're just going to have a &lt;code&gt;Activity&lt;/code&gt; that shows a &lt;code&gt;TextView&lt;/code&gt;. The requirements for this new &lt;code&gt;Activity&lt;/code&gt; are as follows:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;If the &lt;code&gt;Intent&lt;/code&gt; used to start it &lt;em&gt;DOES NOT&lt;/em&gt; have the "text" string extra, then show "Hello World!"&lt;/li&gt;
&lt;li&gt;If the &lt;code&gt;Intent&lt;/code&gt; used to start it &lt;em&gt;DOES&lt;/em&gt; have the "text" string extra, then show whatever is in that extra&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;So to get started, do the following:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create a new project via AndroidStudio&lt;/li&gt;
&lt;li&gt;Select the Empty Activity option&lt;/li&gt;
&lt;li&gt;Open the generated activity_main.xml layout file and add the following attribute to the &lt;code&gt;TextView&lt;/code&gt; element: &lt;code&gt;android:id="@+id/hello"&lt;/code&gt; (which will allow us to reference it in the test and in the &lt;code&gt;MainActivity&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Add the following &lt;code&gt;androidTestImplementation&lt;/code&gt; dependency to your app's build.gradle file: &lt;code&gt;androidTestImplementation 'androidx.test:rules:1.1.0'&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Now that you have the setup in-place, Create a new class in the &lt;code&gt;androidTest&lt;/code&gt; source set:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@RunWith&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;AndroidJUnit4&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MainActivityTest&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="nd"&gt;@Rule&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;ActivityTestRule&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;MainActivity&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;rule&lt;/span&gt;
            &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ActivityTestRule&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;(&lt;/span&gt;&lt;span class="nc"&gt;MainActivity&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

    &lt;span class="nd"&gt;@Test&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;shouldShowHelloWorldByDefault&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;Espresso&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;onView&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ViewMatchers&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;withId&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;R&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;hello&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;check&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ViewAssertions&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;matches&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ViewMatchers&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;withText&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Hello World!"&lt;/span&gt;&lt;span class="o"&gt;)));&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This test is good enough to test the default case. And it passes! And it was pretty easy to write. So far so good!&lt;/p&gt;

&lt;p&gt;What about the non-default case? Alright--lets customize the &lt;code&gt;Intent&lt;/code&gt; we send into the &lt;code&gt;Activity&lt;/code&gt;. In order to do that, we'll create an inline extension of &lt;code&gt;ActivityTestRule&lt;/code&gt; that overrides the &lt;code&gt;getActivityIntent()&lt;/code&gt; method:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@RunWith&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;AndroidJUnit4&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MainActivityTest&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="nd"&gt;@Rule&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;ActivityTestRule&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;MainActivity&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;rule&lt;/span&gt;
            &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ActivityTestRule&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;MainActivity&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="nc"&gt;MainActivity&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nd"&gt;@Override&lt;/span&gt;
        &lt;span class="kd"&gt;protected&lt;/span&gt; &lt;span class="nc"&gt;Intent&lt;/span&gt; &lt;span class="nf"&gt;getActivityIntent&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Intent&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;getApplicationContext&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="nc"&gt;MainActivity&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;putExtra&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Goodbye, Cruel World!"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;};&lt;/span&gt;

    &lt;span class="nd"&gt;@Test&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;shouldShowHelloWorldByDefault&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;Espresso&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;onView&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ViewMatchers&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;withId&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;R&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;hello&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;check&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ViewAssertions&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;matches&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ViewMatchers&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;withText&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Hello World!"&lt;/span&gt;&lt;span class="o"&gt;)));&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;That was easy enough, and our test still passes, but it really shouldn't. It passes because we haven't actually updated the &lt;code&gt;MainActivity&lt;/code&gt; to set the text by the intent. Lets do that:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MainActivity&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;AppCompatActivity&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="nd"&gt;@Override&lt;/span&gt;
    &lt;span class="kd"&gt;protected&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;onCreate&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Bundle&lt;/span&gt; &lt;span class="n"&gt;savedInstanceState&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;super&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;onCreate&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;savedInstanceState&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;setContentView&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;R&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;layout&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;activity_main&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

        &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;getIntent&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;getStringExtra&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="o"&gt;((&lt;/span&gt;&lt;span class="nc"&gt;TextView&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="n"&gt;findViewById&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;R&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;hello&lt;/span&gt;&lt;span class="o"&gt;)).&lt;/span&gt;&lt;span class="na"&gt;setText&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;That should be enough to support the requirements of the &lt;code&gt;MainActivity&lt;/code&gt;, but now our test, correctly, fails. Lets just ignore that test for now and write a test that will expect "Goodbye, Cruel World!" to be shown:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@RunWith&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;AndroidJUnit4&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MainActivityTest&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="nd"&gt;@Rule&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;ActivityTestRule&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;MainActivity&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;rule&lt;/span&gt;
            &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ActivityTestRule&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;MainActivity&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="nc"&gt;MainActivity&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nd"&gt;@Override&lt;/span&gt;
        &lt;span class="kd"&gt;protected&lt;/span&gt; &lt;span class="nc"&gt;Intent&lt;/span&gt; &lt;span class="nf"&gt;getActivityIntent&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Intent&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;getApplicationContext&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="nc"&gt;MainActivity&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;putExtra&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Goodbye, Cruel World!"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;};&lt;/span&gt;

    &lt;span class="nd"&gt;@Ignore&lt;/span&gt;
    &lt;span class="nd"&gt;@Test&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;shouldShowHelloWorldByDefault&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;Espresso&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;onView&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ViewMatchers&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;withId&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;R&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;hello&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;check&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ViewAssertions&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;matches&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ViewMatchers&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;withText&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Hello World!"&lt;/span&gt;&lt;span class="o"&gt;)));&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@Test&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;shouldShowTextFromExtraInIntent&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;Espresso&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;onView&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ViewMatchers&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;withId&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;R&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;hello&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;check&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ViewAssertions&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;matches&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ViewMatchers&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;withText&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Goodbye, Cruel World!"&lt;/span&gt;&lt;span class="o"&gt;)));&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;So we've got a problem testing more than one case in the same test class. Now that the problem has been established, why is it a problem? The answer is that the lifecycle of your JUnit4 test starts &lt;em&gt;AFTER&lt;/em&gt; the Activity you're testing has been resumed.&lt;/p&gt;

&lt;p&gt;Don't worry--we're going to solve this problem.&lt;/p&gt;

&lt;h2&gt;
  
  
  A few naive approaches
&lt;/h2&gt;

&lt;p&gt;One could imagine a few different ways to solve this issue. Here are a couple naive ways:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create a test class for each intent that you want to send to launch the Activity&lt;/li&gt;
&lt;li&gt;Delay the launch of the activity you're testing by starting the activity you want to test from an intermediate activity.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Why are these approaches naive?
&lt;/h3&gt;

&lt;p&gt;Creating a new test class for each intent you want to use will work for you only if the number of cases is low. For example, there are three cases that we need to test:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The default case&lt;/li&gt;
&lt;li&gt;The non-default case&lt;/li&gt;
&lt;li&gt;The non-default case with a different value than in case 2 (to ensure that the source of the string was, indeed the intent extra)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;However, as the number of cases proliferate, it could get laborious to maintain all of those test classes.&lt;/p&gt;

&lt;p&gt;Delaying the launch of the activity under test by using an intermediary is one way to work around the proliferation of classes and copied code. However, there are two reasons why this solution is not the best:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;You have to launch an activity that you don't intend to test in order to test the activity you intend to test. Thus, you need to create this dummy &lt;code&gt;Activity&lt;/code&gt; class.&lt;/li&gt;
&lt;li&gt;This approach works best with the &lt;code&gt;ActivityTestRule&lt;/code&gt; constructor that launches the activity once per test class instead of launching a new activity per test. Doing so opens the door to leaking state between tests.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Some better solutions
&lt;/h2&gt;

&lt;p&gt;The following are two better solutions:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;(not recommended) Use the JUnit4 &lt;code&gt;Parameterized&lt;/code&gt; test runner and constructor arguments to parameterize your test. See the drawbacks of this approach below.&lt;/li&gt;
&lt;li&gt;Write a custom &lt;code&gt;RUNTIME&lt;/code&gt; retention annotation that you then read when the &lt;code&gt;ActivityTestRule&lt;/code&gt; is applied.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  The JUnit4 Parameterized Runner approach
&lt;/h3&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@RunWith&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Parameterized&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MainActivityTest&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;extraText&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;expectedText&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;MainActivityTest&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;extraText&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;expectedText&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;extraText&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;extraText&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;expectedText&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;expectedText&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@Rule&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;ActivityTestRule&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;MainActivity&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;rule&lt;/span&gt;
            &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ActivityTestRule&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;MainActivity&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="nc"&gt;MainActivity&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nd"&gt;@Override&lt;/span&gt;
        &lt;span class="kd"&gt;protected&lt;/span&gt; &lt;span class="nc"&gt;Intent&lt;/span&gt; &lt;span class="nf"&gt;getActivityIntent&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Intent&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;getApplicationContext&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="nc"&gt;MainActivity&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;putExtra&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;extraText&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

        &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;};&lt;/span&gt;

    &lt;span class="nd"&gt;@Parameterized&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Parameters&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="nc"&gt;Iterable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Object&lt;/span&gt;&lt;span class="o"&gt;[]&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;data&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;Arrays&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;asList&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Object&lt;/span&gt;&lt;span class="o"&gt;[][]&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="o"&gt;{&lt;/span&gt;
                        &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                        &lt;span class="s"&gt;"Hello World!"&lt;/span&gt;
                &lt;span class="o"&gt;},&lt;/span&gt;
                &lt;span class="o"&gt;{&lt;/span&gt;
                        &lt;span class="s"&gt;"string1"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                        &lt;span class="s"&gt;"string1"&lt;/span&gt;
                &lt;span class="o"&gt;},&lt;/span&gt;
                &lt;span class="o"&gt;{&lt;/span&gt;
                        &lt;span class="s"&gt;"string2"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                        &lt;span class="s"&gt;"string2"&lt;/span&gt;
                &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="o"&gt;});&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;


    &lt;span class="nd"&gt;@Test&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;shouldShowCorrectText&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;Espresso&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;onView&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ViewMatchers&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;withId&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;R&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;hello&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;check&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ViewAssertions&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;matches&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ViewMatchers&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;withText&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;expectedText&lt;/span&gt;&lt;span class="o"&gt;)));&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This will work and it will cover all of our cases, but I don't love this approach. The &lt;code&gt;Parameterized&lt;/code&gt; JUnit4 Runner does not delegate to the test runner that you configure via your build system. Furthermore, you cannot name your test methods appropriately. The above example has the following test names: &lt;code&gt;shouldShowCorrectText[0]&lt;/code&gt;, &lt;code&gt;shouldShowCorrectText[1]&lt;/code&gt;, and &lt;code&gt;shouldShowCorrectText[2]&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Custom RUNTIME Annotation approach
&lt;/h3&gt;

&lt;p&gt;So lets write this test class in a way that uses the &lt;code&gt;AndroidJUnit4&lt;/code&gt; runner and create sensible test names:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@RunWith&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;AndroidJUnit4&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MainActivityTest&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="nd"&gt;@Retention&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;RetentionPolicy&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;RUNTIME&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nd"&gt;@interface&lt;/span&gt; &lt;span class="nc"&gt;TestConfig&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;extraText&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nc"&gt;TestConfig&lt;/span&gt; &lt;span class="n"&gt;testConfig&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="nd"&gt;@Rule&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;ActivityTestRule&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;MainActivity&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;rule&lt;/span&gt;
            &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ActivityTestRule&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;MainActivity&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="nc"&gt;MainActivity&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

        &lt;span class="nd"&gt;@Override&lt;/span&gt;
        &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;Statement&lt;/span&gt; &lt;span class="nf"&gt;apply&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Statement&lt;/span&gt; &lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Description&lt;/span&gt; &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="nc"&gt;Method&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;MainActivityTest&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getDeclaredMethod&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getMethodName&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
                &lt;span class="n"&gt;testConfig&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getAnnotation&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;TestConfig&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kd"&gt;super&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;apply&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Exception&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;RuntimeException&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;

        &lt;span class="nd"&gt;@Override&lt;/span&gt;
        &lt;span class="kd"&gt;protected&lt;/span&gt; &lt;span class="nc"&gt;Intent&lt;/span&gt; &lt;span class="nf"&gt;getActivityIntent&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;testConfig&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kd"&gt;super&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getActivityIntent&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Intent&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;getApplicationContext&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="nc"&gt;MainActivity&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;putExtra&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;testConfig&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;extraText&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;

        &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;};&lt;/span&gt;

    &lt;span class="nd"&gt;@Test&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;shouldShowHelloWorldByDefault&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;verifyText&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Hello World!"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@Test&lt;/span&gt;
    &lt;span class="nd"&gt;@TestConfig&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;extraText&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Goodbye, Cruel World!"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;shouldShowCorrectTextFromExtraWhenSet&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;verifyText&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;testConfig&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;extraText&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@Test&lt;/span&gt;
    &lt;span class="nd"&gt;@TestConfig&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;extraText&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Hello, Wonderful World!"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;shouldShowCorrectTextFromExtraWhenSetToSomethingElse&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;verifyText&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;testConfig&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;extraText&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;verifyText&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;Espresso&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;onView&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ViewMatchers&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;withId&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;R&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;hello&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;check&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ViewAssertions&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;matches&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ViewMatchers&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;withText&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="o"&gt;)));&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Notice that the &lt;code&gt;Description&lt;/code&gt; of the test in the &lt;code&gt;apply(Statement, Description)&lt;/code&gt; method comes with the name of the current test method. Therefore, you can get a reference to the &lt;code&gt;Method&lt;/code&gt; object and access its annotations.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Because the &lt;code&gt;JUnit4&lt;/code&gt; test lifecycle starts &lt;em&gt;AFTER&lt;/em&gt; the &lt;code&gt;Activity&lt;/code&gt; under test is resumed, it can be difficult to configure the behavior of the activity prior to the point you can interact with it in the test. There are a few approaches for dealing with this situation, but using a custom &lt;code&gt;RUNTIME&lt;/code&gt; annotation can help you configure the test prior to the activity launching with relatively few drawbacks.&lt;/p&gt;

</description>
      <category>android</category>
      <category>activitytestrule</category>
      <category>junit4</category>
      <category>testing</category>
    </item>
    <item>
      <title>Kotlin/Java Annotations: They're where it's @</title>
      <dc:creator>Ryan</dc:creator>
      <pubDate>Sat, 11 Jan 2020 22:22:05 +0000</pubDate>
      <link>https://dev.to/ryansgot/kotlin-java-annotations-they-re-where-it-s-anl</link>
      <guid>https://dev.to/ryansgot/kotlin-java-annotations-they-re-where-it-s-anl</guid>
      <description>&lt;p&gt;I had an interesting conversation with a colleague recently about the use of annotations in Java/Kotlin code. He had worked in organizations where the use of some language features (in this case, meta-programming via annotations) was discouraged as being "too magical" and "difficult to understand." While it's reasonable to choose to avoid some features of a framework or language because they are generally considered harmful, one developer's "magic" is another developer's everyday productivity tool.&lt;/p&gt;

&lt;p&gt;I'll restate the objection to "magic" in a different way:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I don't understand this feature of the language, and therefore I choose to not use it--without regard to its intended usage or possible productivity benefits.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;As developers, it's our job to understand both when and how to use the tools we have at our disposal to solve the problems we solve with software. Therefore, keeping an open mind to leverage the features of the language and frameworks we use can be a great productivity aid. This article covers some of the applications of annotations in Kotlin and Java and proposes a few ways to categorize the annotations you see so that you can infer their intended usage.&lt;/p&gt;

&lt;h2&gt;
  
  
  What are Annotations For?
&lt;/h2&gt;

&lt;p&gt;At a high level, annotations give the compiler information about the code that it is compiling so that the programmer can change its behavior (which is why we use the term "metaprogramming") or to provide extra information about the running code at runtime. Some annotations can serve to generate compilation errors or warnings or even to generate more code for the compiler to compile when combined with annotation processors (which operate at compile time).&lt;/p&gt;

&lt;p&gt;Because of this, the properties of the annotations can only be other annotations or values (primitives, strings, arrays of primitives/strings, classes).&lt;/p&gt;

&lt;h2&gt;
  
  
  What Generic Benefit do Annotations provide?
&lt;/h2&gt;

&lt;p&gt;With annotations, you can write code that is more concise and declarative, and likely less error-prone. They can also enhance the readability of the code by indicating to the developer how the code should be used.&lt;/p&gt;

&lt;h2&gt;
  
  
  How are Annotations used?
&lt;/h2&gt;

&lt;p&gt;As far as I can tell, their usages can be broken down into the following three categories (I'm using my own nomenclature):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Markers (BINARY/CLASS)&lt;/li&gt;
&lt;li&gt;Enrichers (RUNTIME)&lt;/li&gt;
&lt;li&gt;Generators (SOURCE)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Markers
&lt;/h2&gt;

&lt;p&gt;Markers are not very sexy, but they are still important. They both inform the reader (of the code) about the nature of the language element (think class, type, field/property. etc) that has been annotated and inform static analysis tools or the compiler about an annotated element. They always included in the class files (this is what is meant by the &lt;code&gt;AnnotationRetention.BINARY&lt;/code&gt;/&lt;code&gt;RetentionPolicy.CLASS&lt;/code&gt; enum) so that their usages are published with any jar file that is created from the code.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;@Deprecated&lt;/code&gt; in Java is a marker that is intended to tell a developer that this Element is going to go away, and writing any new code consuming that Element could possibly add more work for you in the future as you will be forced to migrate (usually upon a major version update). Some IDEs use this annotation to make it plain to the user that the element is deprecated. &lt;code&gt;@Deprecated&lt;/code&gt; in Kotlin has been enhanced to allow the developer to provide a &lt;code&gt;@ReplaceWith&lt;/code&gt; member that will allow some IDEs (IntelliJ/Android Studio) to intelligently replace deprecated code with non-deprecated code. But mostly, this is a tool for the reader of the code.&lt;/p&gt;

&lt;p&gt;Another useful marker annotation in Java (even though it has RetentionPolicy.RUNTIME) is &lt;code&gt;@Nonnull&lt;/code&gt; (which is part of the outcome of &lt;a href="https://jcp.org/en/jsr/detail?id=305"&gt;JSR-305&lt;/a&gt;). If you use google's implementation, this annotation happens to be useful in Java/Kotlin interop because your Kotlin code will be able to tell that &lt;code&gt;@Nonnull String foo&lt;/code&gt; is &lt;code&gt;String&lt;/code&gt; in Kotlin and not &lt;code&gt;String?&lt;/code&gt;. This also aids in static analysis tooling (such as findbugs) so that null-checks may be skipped. In case you were wondering, this annotation has a companion in &lt;code&gt;@Nullable&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Enrichers
&lt;/h2&gt;

&lt;p&gt;Enrichers add information to a language Element that is readable during runtime (thus, these annotations have &lt;code&gt;AnnotationRetention.RUNTIME&lt;/code&gt;/&lt;code&gt;RetentionPolicy.RUNTIME&lt;/code&gt;). Say, for example, that you were developing a custom XML serialization/deserialization library with the intention of avoiding your consumers needing to write custom serializer/deserializer classes. Then you could use a small set of annotations combined with a single serializer/deserializer that reads the information contained within the annotations on the Element(s) of the classes its intended to serialize to/from. There is a library that does this: &lt;a href="http://simple.sourceforge.net/"&gt;http://simple.sourceforge.net/&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;My personal favorite library that leverages runtime annotations is (Retrofit2)[&lt;a href="https://square.github.io/retrofit/"&gt;https://square.github.io/retrofit/&lt;/a&gt;]. Retrofit2 uses reflection to generate Java Proxy objects capable of performing a network call based solely on your method declaration. For example,&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public interface UserService {
  @POST("users/new")
  Call&amp;lt;User&amp;gt; createUser(@Body User user);
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;@POST&lt;/code&gt; and &lt;code&gt;@Body&lt;/code&gt; annotations are read at runtime when the call is made, and when this call is executed, retrofit will assemble a URL that corresponds to the endpoint in the &lt;code&gt;@POST&lt;/code&gt; annotation and create an OkHttp request that has some serialized form of the &lt;code&gt;User&lt;/code&gt; object in the body of the request. (If you don't know how to configure retrofit to do this, I suggest reading the documentation). &lt;/p&gt;

&lt;p&gt;That's pretty great, right? In particular on Android, &lt;code&gt;AnnotationRetention.RUNTIME&lt;/code&gt;/&lt;code&gt;RetentionPolicy.RUNTIME&lt;/code&gt; annotations have a cost: &lt;a href="https://blog.nimbledroid.com/2016/02/23/slow-Android-reflection.html"&gt;https://blog.nimbledroid.com/2016/02/23/slow-Android-reflection.html&lt;/a&gt;. So before you go wild using them for everything--at least on an Android project, be aware of the costs involved.&lt;/p&gt;

&lt;h2&gt;
  
  
  Generators
&lt;/h2&gt;

&lt;p&gt;Both Kotlin and Java have annotation processing capability. Annotation processors run when your project is compiled (and thus, they alone have visibility into annotations with &lt;code&gt;AnnotationRetention.SOURCE&lt;/code&gt;/&lt;code&gt;RetentionPolicy.SOURCE&lt;/code&gt;). They can do things as simple as add notes that log output to the console or as complicated as generate code to be compiled. Generators are particularly applicable in situations where traditional reuse patterns break down, and are useful in eliminating boilerplate code.&lt;/p&gt;

&lt;p&gt;For example, if you have ever implemented the builder pattern to make instantiation of a class that has many fields easier to understand and more self-documenting, then you're probably familiar with the boilerplate associated with it. You'll find yourself going through a copy-paste-change flow quite often. After 10 or 20 repetitions of this flow, you'll probably have made a mistake somewhere. Then, in order to write reasonable &lt;code&gt;equals&lt;/code&gt;, &lt;code&gt;hashCode&lt;/code&gt;, and &lt;code&gt;toString&lt;/code&gt; methods, you'll have to repeat that flow three more times. You'll also have to write a constructor that understands how to apply the builder to construct your object without accidentally assigning the wrong builder field to the wrong class field.&lt;/p&gt;

&lt;p&gt;Enter Google's awesome AutoValue annotation processor: &lt;a href="https://github.com/google/auto/blob/master/value/userguide/builders.md"&gt;https://github.com/google/auto/blob/master/value/userguide/builders.md&lt;/a&gt;. This tool enables you to declare an abstract version of your class and an abstract version of the builder for the class, delegating the implementation details to the annotation processor. Additionally, the &lt;code&gt;equals&lt;/code&gt;, &lt;code&gt;hashCode&lt;/code&gt;, and &lt;code&gt;toString&lt;/code&gt;, methods and the constructor for the class are also generated.&lt;/p&gt;

&lt;p&gt;Suppose you now have to add a field to the class. Instead of worrying about keeping the implementation of the constructor, &lt;code&gt;equals,&lt;/code&gt;hashCode&lt;code&gt;, and&lt;/code&gt;toString` methods up to date, you just have to declare an abstract method for the class and its builder. Next time you compile your code, the actual implementation will be updated.&lt;/p&gt;

&lt;p&gt;But that's not all. AutoValue has been designed to be open for extension, and many AutoValue extensions have been introduced to increase your productivity.&lt;/p&gt;

&lt;p&gt;Serialization is a natural extension of AutoValue, and quite a few extensions generate serializers/deserializers the objects of classes that are generated by AutoValue. I'll highlight &lt;a href="https://github.com/rharter/auto-value-moshi"&gt;auto-value-moshi&lt;/a&gt; in this article as a representative library because there is an additional Kotlin Annotation Processor called &lt;a href="https://github.com/square/moshi#codegen"&gt;moshi-codegen&lt;/a&gt; that will operate on and generate Kotlin classes to serialize/deserialize your Kotlin objects to/from JSON.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;It's important to learn how to apply the tools at your disposal to solve the problems that you face as a software developer. Rather than avoid some tools as "magic," you should apply a little learning to demystify them.&lt;/p&gt;

&lt;p&gt;Annotations are a useful tool to increase your productivity in Kotlin/Java and increase the quality of your code when used appropriately. So the next time you see some Java/Kotlin that has an &lt;code&gt;@&lt;/code&gt;, I hope you'll be more capable of understanding &lt;/p&gt;

</description>
      <category>kotlin</category>
      <category>java</category>
      <category>annotation</category>
    </item>
  </channel>
</rss>
