Android自动化测试

Android自动化测试

enter image description here


摘要

Android自带了很多方便的测试工具和方法,包括我们常用的单元测试、UI测试、Monkey测试、Robotium测试、MonkeyRunner测试、senevent模拟等。这些API对于我们编写高质量的APP十分有用。一方面可以发现一些隐藏问题,另一方面可以使测试过程规范化。综合以上原因,本文将分别针对Monkey测试、单元测试以及UI测试进行介绍。

Monkey测试

简介
Monkey是Android SDK提供的一个命令行工具,可以简单、方便地运行在任何版本的Android模拟器和实体设备上。 Monkey会发送伪随机的用户事件流(如:点击、滑动、按键等,事件类别随机,就和一只猴子在试用你的APP一样,目的只为玩坏它),主要应用于APP的压力和可靠性测试。  
使用方式
(1) Monkey程序由Android系统自带,使用Java语言写成,在Android文件系统中的存放路径是: /system/framework/monkey.jar;   
(2) Monkey.jar程序是由一个名为“monkey”的Shell脚本来启动执行,shell脚本在Android文件系统中 的存放路径是:/system/bin/monkey;  
(3)Monkey 命令启动方式:  

    - 可以通过PC机CMD窗口中执行: adb shell monkey {+命令参数}来进行Monkey测试  
    - 或在Android机或者模拟器上直接执行monkey 命令,可以在Android机上安装Android终端模拟器  
    - 一般使用如下命令:adb shell -p xxx.xxx.com -v 1000 进行测试,其中xxx.xxx.com是要测试的APP的包名         
效果展示

部分输出数据如下所示:
输出数据

更多参数介绍

点击查看

可能会遇到的问题
(1)“'adb' 不是内部或外部命令,也不是可运行的程序或批处理文件。”  

点击查看解决方案

单元测试

简介
单元测试是为了测试某一个代码单元而写的测试代码。“一个代码单元”一般就是一个方法(函数)。总结一下,我们可以这样理解:单元测试,是为了测试某一个类的某一个方法能否正常工作,而写的测试代码。Java单元测试框架:Junit、Mockito、Powermockito等,最开始建议先学习Junit & Mockito。这两款框架是java领域应用非常普及,使用简单,网上文章非常多,官网的说明也很清晰。junit运行在jvm上,所以只能测试纯java,若要测试依赖android库的代码,可以用mockito隔离依赖(下面会谈及)。
使用方式
首先我们的项目要依赖于junit库,Android studio创建项目时会自动引入该库,即在app的build.gradle中的如下语句:

dependencies {
    testCompile 'junit:junit:4.12'
}

而后在test文件下写单元测试类
enter image description here

被测试类如下

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

单元测试类如下

public class ExampleUnitTest {
    @Test
    public void addition_isCorrect() throws Exception {
        assertEquals(4, Calculator.add(2,2));
    }
}

最后运行单元测试类,结果如下:

enter image description here

Junit标签解析

在Junit中有多种标签可供使用,以下是它们的使用时机,以及作用:

@Test: 将方法(函数)标记为测试用例
@Before: 每一个使用@Test标记的方法运行之前都要运行一次
@After: 每一个使用@Test标记的方法运行之后都要运行一次
@BeforeClass: 整个测试类运行过程中,最先运行,且只运行一次
@AfterClass: 整个测试类运行过程中,最后运行,且只运行一次

以如下代码为例:

public class ExampleUnitTest {

    @Test
    public void addition_isCorrect() throws Exception {
        System.out.println("@Test");
    }


    @Test
    public void addition_isErr() throws Exception {
        System.out.println("@Test");
    }

    @Before
    public void before() throws Exception {
        System.out.println("@Before");
    }

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


    @AfterClass
    public static void afterClass() throws Exception {
        System.out.println("@AfterClass");
    }

    @BeforeClass
    public static void beforeClass() throws Exception {
        System.out.println("@BeforeClass");
    }
}

相应的执行顺序如下:
enter image description here

Mockito使用方式

简介:

Mockito 是一个流行 mock 框架(mock 是指类或者接口的模拟实现,你可以自定义一个对象中某个方法的输出结果),可以和JUnit结合起来使用。Mockito 允许你创建和配置 mock 对象,并且定义它的行为。使用Mockito可以明显的简化对外部依赖的测试类的开发。

先体验以下Mockito的使用:

1.添加依赖

testCompile 'org.mockito:mockito-core:2.8.47'

2.被依赖类

public interface IMathUtils {
    public int abs(int num); // 求绝对值
}

3.依赖类

@RunWith(MockitoJUnitRunner.class)
public class MockTest {
    @Mock
    IMathUtils mathUtils;

    @Test
    public void mockTest() {

        when(mathUtils.abs(-1)).thenReturn(1); // 当调用abs(-1)时,返回1

        int abs = mathUtils.abs(-1); // 输出结果 1

        Assert.assertEquals(abs, 1);// 测试通过
    }
}

可以发现IMathUtils是一个接口,根本就没有实现,用Mockito框架mock之后,IMathUtils.abs(-1)就有返回值1了。这就是Mockito神奇的地方!Mockito代理了IMathUtils.abs(num)的行为,只要调用时符合指定参数(代码中指定参数-1),就可以得到映射的返回值。

Mockito的语法when…thenReturn…相当直观,直观解释就是当调用某个过程时,返回固定的结果。

上述的依赖类也可以使用如下方式来写:

public class MockTest {

    @Mock
    IMathUtils iMathUtils ; 

    @Rule public MockitoRule mockitoRule = MockitoJUnit.rule(); 

    @Test
    public void mockTest()  {
        when(mathUtils.abs(-1)).thenReturn(1); // 当调用abs(-1)时,返回1

        int abs = mathUtils.abs(-1); // 输出结果 1

        Assert.assertEquals(abs, 1);// 测试通过
    }
}

其中@Rule public MockitoRule mockitoRule = MockitoJUnit.rule(); 用于初始化Mock对象,效果与在类前添加@RunWith(MockitoJUnitRunner.class)标签类似

Mock配置

Mock有多种配置方式,如下所示:

@Test
public void test1()  {
        //  创建 mock
        MyClass test = Mockito.mock(MyClass.class);

    // 自定义 getUniqueId() 的返回值
    when(test.getUniqueId()).thenReturn(43);

    // 在测试中使用mock对象
    assertEquals(test.getUniqueId(), 43);
}

// 返回多个值
@Test
public void testMoreThanOneReturnValue()  {
        Iterator i= mock(Iterator.class);
        when(i.next()).thenReturn("Mockito").thenReturn("rocks");
        String result=i.next()+" "+i.next();
        // 断言
        assertEquals("Mockito rocks", result);
}

// 如何根据输入来返回值
@Test
public void testReturnValueDependentOnMethodParameter()  {
        Comparable c= mock(Comparable.class);
        when(c.compareTo("Mockito")).thenReturn(1);
        when(c.compareTo("Eclipse")).thenReturn(2);
        // 断言
        assertEquals(1,c.compareTo("Mockito"));
}

// 如何让返回值不依赖于输入
@Test
public void testReturnValueInDependentOnMethodParameter()  {
        Comparable c= mock(Comparable.class);
        when(c.compareTo(anyInt())).thenReturn(-1);
        // 断言
        assertEquals(-1 ,c.compareTo(9));
}

// 根据参数类型来返回值
@Test
public void testReturnValueInDependentOnMethodParameter()  {
        Comparable c= mock(Comparable.class);
        when(c.compareTo(isA(Todo.class))).thenReturn(0);
        // 断言
        Todo todo = new Todo(5);
        assertEquals(todo ,c.compareTo(new Todo(1)));
}

更多配置可以看下这个网站 点击链接

UI测试

简介
UI测试顾名思义就是:开发人员可以对已经安装到手机或模拟器上的APP进行功能性的测试。现在Android studio自带的Espresso就是一个很好的UI测试框架。
使用方式

1.配置Espresso依赖,现在Android Studio都会在项目创建时自动导入。

testCompile 'com.android.support.test.espresso:espresso-core:2.2.2'
testCompile 'com.android.support.test:runner:0.4.1'

2.在androidTest目录下创建测试类

enter image description here

3.被测试类(即activity之类的展示界面)
MainActivity.class

public class MainActivity extends AppCompatActivity implements View.OnClickListener{

    private EditText mEt;
    private TextView mTv;
    private Button mBtn;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mEt = (EditText) findViewById(R.id.et);
        mTv = (TextView) findViewById(R.id.tv);
        mBtn = (Button) findViewById(R.id.btn);

        mBtn.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        mTv.setText(mEt.getText().toString());
    }
}

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    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="xgn.com.androidautotest.MainActivity">

<TextView
    android:id="@+id/tv"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_marginTop="15dp"
    android:padding="10dp"
    android:text="helo" />

<EditText
    android:id="@+id/et"
    android:layout_width="match_parent"
    android:layout_height="40dp"
    android:layout_alignParentLeft="true"
    android:layout_alignParentStart="true"
    android:layout_alignParentTop="true"
    android:layout_marginTop="75dp" />

<Button
    android:id="@+id/btn"
    android:layout_width="80dp"
    android:layout_height="wrap_content"
    android:layout_below="@+id/et"
    android:layout_centerHorizontal="true"
    android:layout_marginTop="49dp"
    android:text="sure" />
</RelativeLayout>

测试类
ExampleInstrumentedTest.class

@RunWith(AndroidJUnit4.class)
public class ExampleInstrumentedTest {
    @Rule
    public ActivityTestRule<MainActivity> mActivityRule = new ActivityTestRule<>(
            MainActivity.class);

    @Test
    public void useAppContext() throws Exception {
        // Context of the app under test.
        onView(withId(R.id.et)).perform(typeText("helo world"),
                closeSoftKeyboard());
        onView(withId(R.id.btn)).perform(click());
    }
}

其中onView(withId(R.id.et)).perform(typeText(“helo world”), closeSoftKeyboard());选择界面中的输入框,并输入“helo world”,onView(withId(R.id.btn)).perform(click());选择界面中的按钮并点击。

更多操作方式-1
更多操作方式-2

标签解析
@Rule: 应用于成员变量
@ClassRule: 应用于测试类中的静态变量
两者共同点:这些变量必须是TestRule接口的实例,且访问修饰符必须为public。

@RunWith(AndroidJUnit4.class):  用于修改测试运行器

总结

总的来说自动化测试能够很大程度上减少开发者在测试APP上所消耗的事件,一个好的测试用例能够使APP更可靠,也可以使开发者对自己的作品更有信心。各种测试方式能够搭配使用,合理的配合能够使测试的效果达到最大化。

Android自动化测试

enter image description here

Android自动化测试
摘要
Monkey测试
简介
使用方式
效果展示
更多参数介绍
可能会遇到的问题
单元测试
简介
使用方式
Junit标签解析
Mockito使用方式
UI测试
简介
使用方式
标签解析
总结
摘要

Android自带了很多方便的测试工具和方法,包括我们常用的单元测试、UI测试、Monkey测试、Robotium测试、MonkeyRunner测试、senevent模拟等。这些API对于我们编写高质量的APP十分有用。一方面可以发现一些隐藏问题,另一方面可以使测试过程规范化。综合以上原因,本文将分别针对Monkey测试、单元测试以及UI测试进行介绍。
Monkey测试

简介

Monkey是Android SDK提供的一个命令行工具,可以简单、方便地运行在任何版本的Android模拟器和实体设备上。 Monkey会发送伪随机的用户事件流(如:点击、滑动、按键等,事件类别随机,就和一只猴子在试用你的APP一样,目的只为玩坏它),主要应用于APP的压力和可靠性测试。
使用方式

(1) Monkey程序由Android系统自带,使用Java语言写成,在Android文件系统中的存放路径是: /system/framework/monkey.jar;
(2) Monkey.jar程序是由一个名为“monkey”的Shell脚本来启动执行,shell脚本在Android文件系统中 的存放路径是:/system/bin/monkey;
(3)Monkey 命令启动方式:

- 可以通过PC机CMD窗口中执行: adb shell monkey {+命令参数}来进行Monkey测试  
- 或在Android机或者模拟器上直接执行monkey 命令,可以在Android机上安装Android终端模拟器  
- 一般使用如下命令:adb shell -p xxx.xxx.com -v 1000 进行测试,其中xxx.xxx.com是要测试的APP的包名         

效果展示

部分输出数据如下所示:

输出数据

更多参数介绍

点击查看

可能会遇到的问题

(1)“’adb’ 不是内部或外部命令,也不是可运行的程序或批处理文件。”
点击查看解决方案

单元测试

简介

单元测试是为了测试某一个代码单元而写的测试代码。“一个代码单元”一般就是一个方法(函数)。总结一下,我们可以这样理解:单元测试,是为了测试某一个类的某一个方法能否正常工作,而写的测试代码。Java单元测试框架:Junit、Mockito、Powermockito等,最开始建议先学习Junit & Mockito。这两款框架是java领域应用非常普及,使用简单,网上文章非常多,官网的说明也很清晰。junit运行在jvm上,所以只能测试纯java,若要测试依赖android库的代码,可以用mockito隔离依赖(下面会谈及)。
使用方式

首先我们的项目要依赖于junit库,Android studio创建项目时会自动引入该库,即在app的build.gradle中的如下语句:

dependencies {
testCompile ‘junit:junit:4.12’
}
而后在test文件下写单元测试类

enter image description here

被测试类如下

public class Calculator {
public static int add(int a, int b) {
return a + b;
}
}
单元测试类如下

public class ExampleUnitTest {
@Test
public void addition_isCorrect() throws Exception {
assertEquals(4, Calculator.add(2,2));
}
}
最后运行单元测试类,结果如下:

enter image description here

Junit标签解析

在Junit中有多种标签可供使用,以下是它们的使用时机,以及作用:

@Test: 将方法(函数)标记为测试用例
@Before: 每一个使用@Test标记的方法运行之前都要运行一次
@After: 每一个使用@Test标记的方法运行之后都要运行一次
@BeforeClass: 整个测试类运行过程中,最先运行,且只运行一次
@AfterClass: 整个测试类运行过程中,最后运行,且只运行一次
以如下代码为例:

public class ExampleUnitTest {

@Test
public void addition_isCorrect() throws Exception {
    System.out.println("@Test");
}


@Test
public void addition_isErr() throws Exception {
    System.out.println("@Test");
}

@Before
public void before() throws Exception {
    System.out.println("@Before");
}

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


@AfterClass
public static void afterClass() throws Exception {
    System.out.println("@AfterClass");
}

@BeforeClass
public static void beforeClass() throws Exception {
    System.out.println("@BeforeClass");
}

}
相应的执行顺序如下:

enter image description here

Mockito使用方式

简介:

Mockito 是一个流行 mock 框架(mock 是指类或者接口的模拟实现,你可以自定义一个对象中某个方法的输出结果),可以和JUnit结合起来使用。Mockito 允许你创建和配置 mock 对象,并且定义它的行为。使用Mockito可以明显的简化对外部依赖的测试类的开发。
先体验以下Mockito的使用:

1.添加依赖

testCompile ‘org.mockito:mockito-core:2.8.47’
2.被依赖类

public interface IMathUtils {
public int abs(int num); // 求绝对值
}
3.依赖类

@RunWith(MockitoJUnitRunner.class)
public class MockTest {
@Mock
IMathUtils mathUtils;

@Test
public void mockTest() {

    when(mathUtils.abs(-1)).thenReturn(1); // 当调用abs(-1)时,返回1

    int abs = mathUtils.abs(-1); // 输出结果 1

    Assert.assertEquals(abs, 1);// 测试通过
}

}
可以发现IMathUtils是一个接口,根本就没有实现,用Mockito框架mock之后,IMathUtils.abs(-1)就有返回值1了。这就是Mockito神奇的地方!Mockito代理了IMathUtils.abs(num)的行为,只要调用时符合指定参数(代码中指定参数-1),就可以得到映射的返回值。

Mockito的语法when…thenReturn…相当直观,直观解释就是当调用某个过程时,返回固定的结果。

上述的依赖类也可以使用如下方式来写:

public class MockTest {

@Mock
IMathUtils iMathUtils ; 

@Rule public MockitoRule mockitoRule = MockitoJUnit.rule(); 

@Test
public void mockTest()  {
    when(mathUtils.abs(-1)).thenReturn(1); // 当调用abs(-1)时,返回1

    int abs = mathUtils.abs(-1); // 输出结果 1

    Assert.assertEquals(abs, 1);// 测试通过
}

}
其中@Rule public MockitoRule mockitoRule = MockitoJUnit.rule(); 用于初始化Mock对象,效果与在类前添加@RunWith(MockitoJUnitRunner.class)标签类似

Mock配置

Mock有多种配置方式,如下所示:

@Test
public void test1() {
// 创建 mock
MyClass test = Mockito.mock(MyClass.class);

// 自定义 getUniqueId() 的返回值
when(test.getUniqueId()).thenReturn(43);

// 在测试中使用mock对象
assertEquals(test.getUniqueId(), 43);

}

// 返回多个值
@Test
public void testMoreThanOneReturnValue() {
Iterator i= mock(Iterator.class);
when(i.next()).thenReturn(“Mockito”).thenReturn(“rocks”);
String result=i.next()+” “+i.next();
// 断言
assertEquals(“Mockito rocks”, result);
}

// 如何根据输入来返回值
@Test
public void testReturnValueDependentOnMethodParameter() {
Comparable c= mock(Comparable.class);
when(c.compareTo(“Mockito”)).thenReturn(1);
when(c.compareTo(“Eclipse”)).thenReturn(2);
// 断言
assertEquals(1,c.compareTo(“Mockito”));
}

// 如何让返回值不依赖于输入
@Test
public void testReturnValueInDependentOnMethodParameter() {
Comparable c= mock(Comparable.class);
when(c.compareTo(anyInt())).thenReturn(-1);
// 断言
assertEquals(-1 ,c.compareTo(9));
}

// 根据参数类型来返回值
@Test
public void testReturnValueInDependentOnMethodParameter() {
Comparable c= mock(Comparable.class);
when(c.compareTo(isA(Todo.class))).thenReturn(0);
// 断言
Todo todo = new Todo(5);
assertEquals(todo ,c.compareTo(new Todo(1)));
}
更多配置可以看下这个网站 点击链接

UI测试

简介

UI测试顾名思义就是:开发人员可以对已经安装到手机或模拟器上的APP进行功能性的测试。现在Android studio自带的Espresso就是一个很好的UI测试框架。
使用方式

1.配置Espresso依赖,现在Android Studio都会在项目创建时自动导入。

testCompile ‘com.android.support.test.espresso:espresso-core:2.2.2’
testCompile ‘com.android.support.test:runner:0.4.1’
2.在androidTest目录下创建测试类

enter image description here

3.被测试类(即activity之类的展示界面)
MainActivity.class

public class MainActivity extends AppCompatActivity implements View.OnClickListener{

private EditText mEt;
private TextView mTv;
private Button mBtn;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    mEt = (EditText) findViewById(R.id.et);
    mTv = (TextView) findViewById(R.id.tv);
    mBtn = (Button) findViewById(R.id.btn);

    mBtn.setOnClickListener(this);
}

@Override
public void onClick(View v) {
    mTv.setText(mEt.getText().toString());
}

}
activity_main.xml

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值