Android中的Toast是我们经常会使用的,能够方便的在界面上弹出一个提示语句,还可以控制显示的时长,十分方便。使用Espresso测试Toast的弹出内容不是很好操作,主要由于Toast的布局并不是属于我们当前应用的,而是通过另一个Sevice控制的,这个原理可以看看相关的一些博文,我这里不再详细说明。当时为了测试Toast是否显示正确,也是查了不少文章,最后在Stack Overflow找到了解决的办法,这里给大家介绍一下,但是并不是很完美,后面会详细说明。
我们采用TDD的模式做我们的简单Demo,我们希望界面上有一个文本为点击的按钮,点击该按钮,会弹出一个文本为clicked的Toast,按照这个说明,编写我们的测试代码(项目的Gradle配置见上一篇文章)
package com.yjp.toasttest;
import android.support.test.rule.ActivityTestRule;
import android.support.test.runner.AndroidJUnit4;
import android.widget.Button;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import static android.support.test.espresso.Espresso.onView;
import static android.support.test.espresso.action.ViewActions.click;
import static android.support.test.espresso.assertion.ViewAssertions.matches;
import static android.support.test.espresso.matcher.RootMatchers.withDecorView;
import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
import static android.support.test.espresso.matcher.ViewMatchers.withText;
import static org.hamcrest.Matchers.allOf;
import static org.hamcrest.Matchers.instanceOf;
import static org.hamcrest.Matchers.not;
@RunWith(AndroidJUnit4.class)
public class MainActivityTest {
@Rule
public ActivityTestRule mActivityRule =
new ActivityTestRule<>(MainActivity.class);
@Test
public void testClickButtonToast() throws Exception {
//界面上有一个文本为点击的按钮并点击按钮
onView(allOf(withText(R.string.click), instanceOf(Button.class)))
.check(matches(isDisplayed()))
.perform(click());
//会弹出一个文本为clicked的Toast
Thread.sleep(1000);
onView(withText(R.string.clicked_en))
.inRoot(withDecorView(not(mActivityRule.getActivity().getWindow().getDecorView())))
.check(matches(isDisplayed()));
}
}
首先,我们使用withText和instanceOf两个View Matcher选择出了我们的Button,检查该Button是否显示,执行了click()操作(View Action)。然后我们sleep了1s,这个就是我上面提到的不太完美的地方,如果不加延时,可能Toast会检测不到。休眠1s后,找到Toast的布局,这里通过withText找到对应的Toast的视图,但这无法保证就是Toast
,也有可能在我们的界面中会有其他的控件使用了clicked这个文本,所以,我们还需要保证我们找的Toast视图不在主界面的DecorView中,这里使用了withDecorView和not两个Matcher。最后,通过check检查是否显示。
上面的代码中,我们将点击和clicked两个文本定义为了两个字符串资源,可以看到withText可以直接传递字符串资源。
点击
clicked
现在运行测试,会报错,错误不贴了,意思就是找不到满足条件的按钮,毕竟我们的MainActivity还没有完成。我们完成我们的布局,添加一个按钮,文本为点击(R.string.click)。
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.yjp.toasttest.MainActivity">
android:id="@+id/click_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/click"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.501" />
布局我只是基于项目自动生成的,修改TextView为Button,text设置为点击,我们再次运行测试,这次报错变了,告诉我们找不到Toast的布局。我们添加代码
package com.yjp.toasttest;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button clickButton = (Button) findViewById(R.id.click_button);
clickButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String toast = getString(R.string.clicked_en);
Toast.makeText(MainActivity.this, toast, Toast.LENGTH_SHORT).show();
}
});
}
}
再次运行测试,这次测试通过,说明为我们的代码已经满足了需求的要求。