(4.5.5.7)Espresso之Intent测试

一、Espresso Intents简介

Espresso Intents 是Espresso的扩展,使在测试时应用时验证 Intents 的有效性和发送携带数据的intent成为可能。它与Mockito很像,但是是Android中的意图。

1.1 下载Espresso Intents

  • 确保你安装了Android Support Repository(详情查看 instructions)。

  • 打开你app层的build.gradle文件。这个通常不是顶层的build.gradle文件,而是app层的build.gradle文件。加载下面的依赖:

androidTestCompile 'com.android.support.test.espresso:espresso-intents:2.2.2'Espresso
  • 意图只与Espresso2.1+和测试支持包0.3兼容,所以注意更新下面几行:
androidTestCompile 'com.android.support.test:runner:0.5'

androidTestCompile 'com.android.support.test:rules:0.5'

androidTestCompile 'com.android.support.test.espresso:espresso-core:2.2.2'

1.2 测试规则

Use IntentsTestRule instead of ActivityTestRule when using Espresso-Intents. IntentsTestRule makes it easy to use Espresso-Intents APIs in functional UI tests.
This class is an extension of ActivityTestRule, which initializes Espresso-Intents before each test annotated with @Test and releases Espresso-Intents after each test run.
The activity will be terminated after each test and this rule can be used in the same way as ActivityTestRule.

当使用Espresso意图时使用IntentsTestRule而不是ActivityTestRule 。在进行有效的UI测试时IntentsTestRule使使用Espresso意图更加简便。

在测试完成后,Activity将终止,在ActivityTestRule中也可以以相同的方式使用

1.3 验证 intent的有效性

Espresso-Intents记录了在测试应用时 所有尝试启动的Activity 的 intent.

使用intent的API(类似于Mockito.verify),你可以断言指定的intnet是否被接收

下面是一个简单的验证intent已经发出的的例子:

@Test  
    public void validateIntentSentToPackage() {  
        //用户的动作,结果是启动一个外部的“phone”Activity  
        user.clickOnView(system.getView(R.id.callButton));  

        // Using a canned RecordedIntentMatcher to validate that an intent resolving  
        // to the "phone" activity has been sent.  
        //通过封装的RecordeIntentMatcher来验证作用于“phone” activity的intent已经被发送  
        intended(toPackage("com.android.phone"));  
    }  

1.4 携带参数的intent

使用intent API(类似于Mockito.when),你可以为”通过startActivityForResult方法打开的Activity”设置一个返回结果(对于无法操控用户操作,也不能控制在测试环境下返回结果的activity尤其重要):

下面是携带参数的intent的例子:

@Test  
public void activityResult_IsHandledProperly() {  

    //当activity启动时创建一个将要返回的结果  
    Intent resultData = new Intent();  
    String phoneNumber = "123-345-6789";  
    resultData.putExtra("phone", phoneNumber);  
    ActivityResult result = new ActivityResult(Activity.RESULT_OK, resultData);  


    //当intent发送到com.android.contacts时设置返回结果  
    intending(toPackage("com.android.contacts")).respondWith(result));  


    //"contacts" activity被启动的动作  
    //启动一个activity并返回一个电话号码,显示在屏幕中  
    onView(withId(R.id.pickButton)).perform(click());  


    //断言上面所设置的数据被显示了  
    onView(withId(R.id.phoneNumber).check(matches(withText(phoneNumber)));  
}  

1.6 Intent matchers

intending(..) 和 intended(..)方法都使用 hamcrest Matcher 作为参数。

Hamcrest is library of matcher objects (also known as constraints or predicates). You have these options:

  1. Use an existing intent matcher: Easiest option, which should almost always be preferred.
  2. Implement your own intent matcher: Most flexible option (see the section entitled “Writing custom matchers” in the Hamcrest tutorial)

Hamcrest是matcher对象的library(与constraints和predicates类似)。你有以下选项:

  • 使用一个已经存在匹配器:最简单也是最常用的选择

  • 自定义匹配器:更灵活的选择(更多请查看Hamcrest tutorial部分“自定义匹配器”)

方式一的简单示例,使用已存在的intent匹配器验证intent有效性的例子:

intended(allOf(
    hasAction(equalTo(Intent.ACTION_VIEW)),
    hasCategories(hasItem(equalTo(Intent.CATEGORY_BROWSABLE))),
    hasData(hasHost(equalTo("www.google.com"))),
    hasExtras(allOf(
        hasEntry(equalTo("key1"), equalTo("value1")),
        hasEntry(equalTo("key2"), equalTo("value2")))),
        toPackage("com.android.browser")));

二、示例

2.1 动态发送Intetn

动态启动MainActivity

  • 主界面
public class MainActivity extends AppCompatActivity {  

    @Override  
    protected void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        setContentView(R.layout.activity_main);  
        TextView tv = (TextView) findViewById(R.id.tv_hello);  
        Intent intent = getIntent();  
        String action = intent.getAction();  
        System.out.println("action.................."+action);  
        if (intent.hasExtra("TAG")) {  
            System.out.println("1..................");  
            final String tag = getIntent().getStringExtra("TAG");  
            System.out.println("2.................."+tag);  
            tv.setText(tag);  
            System.out.println("3...................设置成功");  
        }  
    }  
}  
  • 测试文件
@RunWith(AndroidJUnit4.class)  
@SmallTest  
public class MainActivityMultipleLaunchIntentTest {  

    @Rule  
    public ActivityTestRule<MainActivity> mActivityRule =  
            new ActivityTestRule<>(MainActivity.class,      //所要启动的activity  
                                   true,                    //是否初始化toch mode  
                                   true);                  //是否启动activity,为true时,会先以action为main启动activity一次,为false时,会以设置的action启动activity一次,如果不设置,action  

    @Test  
    public void shouldShowHelloMoon() {  
        //模拟要发送的activity  
        Context targetContext = InstrumentationRegistry.getInstrumentation().getTargetContext();  
        Intent intent = new Intent(targetContext, MainActivity.class);  
        intent.putExtra("TAG", "dynamic send intent");  

        //启动目标activity  
        mActivityRule.launchActivity(intent);  

        //检验结果  
        onView(withId(R.id.tv_hello)).check(matches(withText("dynamic send intent")));  
    }  
}  
  • mActivity第三个参数为true时,所运行的结果:目标activity被启动了两次

这里写图片描述

  • mActivity第三个参数为false时的运行结果:目标activity被启动了一次,默认不启动

这里写图片描述

2.2 修改启动activity时所默认使用的inent

  • 主activity中的内容
public class MainActivity extends AppCompatActivity {  

    @Override  
    protected void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        setContentView(R.layout.activity_main);  
        TextView tv = (TextView) findViewById(R.id.tv_hello);  
        if (getIntent().hasExtra("TAG")) {  
            System.out.println("1..................");  
            final String tag = getIntent().getStringExtra("TAG");  
            System.out.println("2.................."+tag);  
            tv.setText(tag);  
            System.out.println("3...................设置成功");  
        }  
    }  
}  
  • 测试文件的内容
@RunWith(AndroidJUnit4.class)  
@SmallTest  
public class CustomIntentTest {  

    @Rule  
    public ActivityTestRule<MainActivity> mActivityRule =  
            new ActivityTestRule<MainActivity>(MainActivity.class) {  
                @Override  
                protected Intent getActivityIntent() {  
                    Context targetContext = InstrumentationRegistry.getInstrumentation().getTargetContext();  
                    Intent result = new Intent(targetContext, MainActivity.class);  
                    result.putExtra("TAG", "custom intent");  
                    return result;  
                }  
            };  

    @Test  
    public void shouldShowHelloEarth() {  

        Context targetContext = InstrumentationRegistry.getInstrumentation().getTargetContext();  
        Intent result = new Intent(targetContext, MainActivity.class);  
        result.putExtra("Name", "Earth");  
  ![这里写图片描述](http://img.blog.csdn.net/20170421100101600?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvZmVpMjAxMjExMDY=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
        onView(withId(R.id.tv_hello)).check(matches(withText("custom intent")));  
    }  
}  
  • 运行结果:

这里写图片描述

2.3 启动activityforResult

见1.4代码

2.4 校验

@Large  
@RunWith(AndroidJUnit4.class)  
public class SimpleIntentTest {  

    private static final String MESSAGE = "This is a test";  
    private static final String PACKAGE_NAME = "com.example.myfirstapp";  

    /* 实例化一个IntentsTestRule对象. */  
    @Rule  
    public IntentsTestRule≶MainActivity> mIntentsRule =  
      new IntentsTestRule≶>(MainActivity.class);  

    @Test  
    public void verifyMessageSentToMessageActivity() {  

        // 在EditText中输入文字.  
        onView(withId(R.id.edit_message))  
                .perform(typeText(MESSAGE), closeSoftKeyboard());  

        // 通过显性的intent向另一个activity发送消息  
        onView(withId(R.id.send_message)).perform(click());  


        //检测目标activity收到了intent中包含的相应包名和消息  
        intended(allOf(  
                hasComponent(hasShortClassName(".DisplayMessageActivity")),  
                toPackage(PACKAGE_NAME),  
                hasExtra(MainActivity.EXTRA_MESSAGE, MESSAGE)));  

    }  
} 

参考文献

Android Intent是一种用于在应用程序之间传递消息的机制。它允许您启动新的Activity、Service或BroadcastReceiver等组件,或者在当前Activity中启动其他应用程序组件。Intent可以携带数据,并且可以在不同的应用程序之间共享。 在Android中,常见的Intent用法包括: 1.启动Activity Intent可以用来启动另一个Activity。例如,您可以使用以下代码启动一个名为"SecondActivity"的Activity: ``` Intent intent = new Intent(this, SecondActivity.class); startActivity(intent); ``` 这将在当前Activity中启动一个新的Activity。 2.传递数据 Intent还可以用来在不同的Activity之间传递数据。例如,您可以使用以下代码将一个字符串数据传递到另一个Activity: ``` Intent intent = new Intent(this, SecondActivity.class); intent.putExtra("message", "Hello from MainActivity"); startActivity(intent); ``` 在接收Activity中,可以使用以下代码获取传递的数据: ``` String message = getIntent().getStringExtra("message"); ``` 3.启动Service Intent可以用来启动另一个Service。例如,您可以使用以下代码启动一个名为"MyService"的Service: ``` Intent intent = new Intent(this, MyService.class); startService(intent); ``` 4.发送Broadcast Intent还可以用来发送Broadcast。例如,您可以使用以下代码发送一个名为"com.example.MY_BROADCAST"的Broadcast: ``` Intent intent = new Intent("com.example.MY_BROADCAST"); sendBroadcast(intent); ``` 这将发送一个Broadcast给所有注册了该Broadcast的应用程序。 5.指定Action Intent可以指定一个Action,以便接收方可以识别它并执行相应的操作。例如,以下代码指定了一个名为"com.example.ACTION_DO_SOMETHING"的Action: ``` Intent intent = new Intent(); intent.setAction("com.example.ACTION_DO_SOMETHING"); startActivity(intent); ``` 在接收方中,可以使用以下代码获取Action: ``` String action = getIntent().getAction(); ``` 6.设置类型 Intent可以设置一个数据类型,以便接收方可以根据该类型来处理数据。例如,以下代码指定了一个MIME类型为"image/jpeg"的数据类型: ``` Intent intent = new Intent(); intent.setType("image/jpeg"); startActivity(intent); ``` 在接收方中,可以使用以下代码获取数据类型: ``` String type = getIntent().getType(); ``` 以上是Android Intent的几种常见用法。使用Intent可以方便地在不同的组件之间传递数据和消息,并且可以执行各种操作。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值