Android单元测试

本文主要内容

  • 1、单元测试介绍
  • 2、java单元测试
  • 3、android单元测试
  • 4、常用方法介绍

1、单元测试介绍

单元测试,是指对软件中的最小可测试单元进行检查和验证。

在Java中,最小单元可以是类也可以是方法,比如刚刚开发完成一个下载的方法,此时可以用单元测试其是否ok。如果不用单元测试,用手写代码调用的方式,则工作量会较大。

使用Android studio进行单元测试,一共有两种类型,一种就是普通的java单元测试,另一种就是android单元测试,android单元测试包括对ui测试,activity的相关方法进行测试等等,需要context参数

《Android单元测试》 image.png

进行单元测试需要引入对应的依赖。

testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
androidTestImplementation 'com.android.support.test:rules:1.0.2'

前面3个依赖包,在创建工程的时候会默认加进来,最后一个貌似不会默认添加,需要手动添加。最后一个依赖包与activity相关的单元测试有关。

2、java单元测试

以一个最简单的例子,计算器为例:

public class Util {

public static int add(int a, int b){
    return a + b;
}

public int addInt(int a, int b){
    return a + b;
}
}

Util类中有一个静态方法,一个非静态方法,都是简单的相加逻辑。接下来,可以右键选中方法,然后点击goto选项,生成对应的单元测试文件。

《Android单元测试》
《Android单元测试》
《Android单元测试》

最后一步中可以选择为当前类中的哪些方法添加单元测试,也可以勾选before和after两个选项,顾名思义,before和after方法分别在单元测试前后调用,我们可以在这两个方法中做一些事情,例如初始化、回收等等。

public class UtilTest {

Util util;

@Before
public void setUp() throws Exception {
    util = new Util();
    System.out.println("sutup");
}

@After
public void tearDown() throws Exception {
    System.out.println("tearDown");
}

@Test
public void add() {
    assertEquals(2,Util.add(1, 1));
}

@Test
public void addInt() {
    assertEquals(2, util.addInt(1,1));
}
}

Util类中,写了一个静态方法和非静态方法,其实就是为了演示 setUp 方法的作用,如果在单元测试中需要初始化一些类,则可以在 setUp 中初始化,在测试方法中使用已经初始化过的实例即可。

Java单元测试运行依赖于 JVM,执行单元测试方法非常简单,右键单元测试文件执行即可,也可以选择某个方法,只执行这一个方法。

3、android单元测试

Android单元测试,它依赖于Android的执行环境,也就是需要在android机器上运行。与java单元测试相比,它有一点点的不同。

前一章中讲过java单元测试,提到了 before 和 after 这两个选项,有点类似于切面编程,可以在其中做一些初始化的动作。但android中最常用的是activity,如何在activity中也添加一些周期回调函数呢?

@Rule
public ActivityTestRule<MainActivity> rule = new ActivityTestRule<MainActivity>(MainActivity.class){
    @Override
    protected Intent getActivityIntent() {
        Intent intent = new Intent();
        intent.putExtra("data","world");
        return intent;
    }

    @Override
    protected void beforeActivityLaunched() {
        super.beforeActivityLaunched();
        Log.i("okunu","before");
    }
};

通过如上方式添加activity相关的单元测试周期回调函数。

getActivityIntent ,顾名思义,对启动activity的intent进行测试封装,上例中就添加了相关的参数。值得注意的是,为何 intent 中没有添加 action 呢?我猜想就是 ActivityTestRule 对象已经与MainActivity相关联了,它就是要去启动MainActivity的,加不加action都无所谓了。这里也隐含了另一层意思,要对某个activity相关的任何方法进行单元测试,都要添加与之相关联的ActivityTestRule 对象。

beforeActivityLaunched ,就是在activity启动之前执行的函数

本例中,有一个EditText,TextView和一个Button,点击Button,将EditText中的文字显示到TextView,同时也会接收Intent中的相关参数,显示在TextView中

public class MainActivity extends AppCompatActivity {

String mData;
TextView text;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    mData = getIntent().getStringExtra("data");
    text = (TextView)findViewById(R.id.text);
    text.setText(mData != null ? mData : "");
}

public void sayHello(View view){
    EditText edit = (EditText)findViewById(R.id.edit);
    String str = "hello  " + mData + " " + edit.getText().toString() + " !";
    text.setText(str);
}
}

它的单元测试类依然可以和第2节一样生成,我们看看详细代码:

@RunWith(AndroidJUnit4.class)
public class MainActivityTest {

@Rule
public ActivityTestRule<MainActivity> rule = new ActivityTestRule<MainActivity>(MainActivity.class){
    @Override
    protected Intent getActivityIntent() {
        Intent intent = new Intent();
        intent.putExtra("data","world");
        return intent;
    }

    @Override
    protected void beforeActivityLaunched() {
        super.beforeActivityLaunched();
        Log.i("okunu","before");
    }
};

Context appContext;
@Before
public void setUp() throws Exception {
    Log.i("okunu","setUp");
    appContext = InstrumentationRegistry.getTargetContext();
}

@After
public void tearDown() throws Exception {
    Log.i("okunu","tearDown");
}

@Test
public void sayHello() {
    onView(withId(R.id.edit)).perform(typeText("jim"), closeSoftKeyboard()); //line 1
    onView(withText("hello")).perform(click()); //line 2
    String expectedText = "hello  " + "world " + "jim" + " !";
    onView(withId(R.id.text)).check(matches(withText(expectedText))); //line 3
}
}

注意,context是可以获取的。另外最重要的就是理解这几个生命周期回调函数的作用。可以在setUp函数中获取context,如果与activity启动相关的要改动,则在ActivityTestRule类中修改即可。

4、常用方法介绍

在android单元测试中需要获取到某个view,如何获取呢?

  • withText:通过文本来获取对象,如:ViewInteraction save = onView(withText(“保存”)) ;
  • withId:通过id来获取对象,如:ViewInteraction save = onView(withId(R.id.save)) ;

通过文本获取,如上例,如果某个view上的文本是“保存”,则返回此view。通过id获取就比较容易理解了,建议使用id方式。

那么对view操作的接口又有哪些呢?

使用方式是onView(…).perform() 。也可以执行多个操作在一个perform中如:perform(click(),clearText()) 。所有的操作都有一个前提 ———— 就是要执行的view必须在当前界面上显示出来(有且可见)。

方法名含义
click()点击view
clearText()清除文本内容
swipeLeft()从右往左滑
swipeRight()从左往右滑
swipeDown()从上往下滑
swipeUp()从下往上滑
click()点击view
closeSoftKeyboard()关闭软键盘
pressBack()按下物理返回键
doubleClick()双击
longClick()长按
scrollTo()滚动
replaceText()替换文本
openLinkWithText()打开指定超链
    原文作者:某昆
    原文地址: https://www.jianshu.com/p/04b23e8d851e
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞