如何为Android开发编写测试
Android应用的自动化单元测试对于其长期质量来说是必要的。单元测试有助于测试代码的一个单元(例如类)。这有助于在开发周期的早期捕获和识别错误或倒退。在这篇文章中,我们将看到如何为我们的Android应用程序编写单元测试。在Android中,单元测试有两种类型:
- 本地单元测试——在开发机器本身上运行,而不是在实际机器上
- 测试单元测试——在实际的Android设备上运行。
用JUnit创建单元测试,用Mockito创建mock对象
我们将首先为一个添加两个数字的Android应用程序创建本地单元测试。
该应用程序包含以下helper类
包com.testsinandroid;进口安卓.支持.注释.VisibleForTesting;公共类NumberAdder{私人最后MainActivitymMainActivity;公共NumberAdder(MainActivity活动){mMainActivity=活动;}公共无效performAddition(){双number1=mMainActivity.getFirstNumber();双科学=mMainActivity.getSecondNumber();如果(!isNumberValid(number1)||!isNumberValid(科学)){扔新RuntimeException(“无效的数字”);}双结果=number1+科学;mMainActivity.setAdditionResult(结果);}@VisibleForTesting布尔isNumberValid(双数量){如果(数量>0){返回真正的;}其他的{返回假;}}}
并且还包含了使用这个类的活动
包com.testsinandroid;进口安卓.应用程序.活动;进口安卓.操作系统.包;进口安卓.视图.视图;进口安卓.小部件.按钮;进口安卓.小部件.EditText;进口安卓.小部件.TextView;公共类MainActivity扩展活动{EditTextfirstNumber;EditTextsecondNumber;TextViewaddResult;按钮btnAdd;NumberAddernumberAdder=零;@Override受保护的无效onCreate(包savedInstanceState){超级.onCreate(savedInstanceState);setContentView(R.布局.activity_main);firstNumber=(EditText)findViewById(R.id.txtNumber1);secondNumber=(EditText)findViewById(R.id.txtNumber2);addResult=(TextView)findViewById(R.id.txtResult);btnAdd=(按钮)findViewById(R.id.btnAdd);如果(numberAdder= =零){numberAdder=新NumberAdder(这);}btnAdd.setOnClickListener(新视图.OnClickListener(){公共无效onClick(视图v){numberAdder.performAddition();}});}公共双getFirstNumber(){返回双.parseDouble(firstNumber.getText().toString());}公共双getSecondNumber(){返回双.parseDouble(secondNumber.getText().toString());}公共无效setAdditionResult(双结果){addResult.setText(双.toString(结果));}}
活动布局如下所示
<使用xmlns:安卓="http://schemas.android.com/apk/res/android"xmlns:工具="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"android:paddingLeft="@dimen / activity_horizontal_margin"android:paddingRight="@dimen / activity_horizontal_margin"android:paddingTop="@dimen / activity_vertical_margin"android:paddingBottom="@dimen / activity_vertical_margin"工具:上下文=".MainActivity"><EditTextandroid:id="@ + id / txtNumber1"android:layout_width="wrap_content"android:layout_height="wrap_content"android:ems="2"android:inputType="数量"><requestFocus/>EditText><EditTextandroid:id="@ + id / txtNumber2"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_below="@ + id / txtNumber1"android:ems="2"android:inputType="数量">EditText><按钮android:id="@ + id / btnAdd"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginTop="46 dp"android:layout_below="@ + id / txtNumber2"android:文本="添加"/><TextViewandroid:id="@ + id / txtResult"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_below="@ + id / btnAdd"android:textAppearance="android: attr / textAppearanceMedium"/>使用>
一旦我们的应用准备好了,我们现在有两个主要单元来测试我们的代码
- NumberAdder——这是一个普通的Java类,它将MainActivity作为一个依赖项。
- MainActivity -显示UI的活动。
作为NumberAdder
是一个普通的Java类,可以使用吗Junit测试这样的类。
JUnit是一个用于编写可重复单元测试的简单框架。当我们测试一个单元(在本例中是NumberAdder)时,可以模拟出NumberAdder所依赖的所有其他类。在Java中模拟依赖关系的一个好框架是5.要在我们的项目中添加JUnit和Mockito作为测试依赖项,请在build.gradle中添加以下内容
dependencies {compile fileTree(dir: 'libs', include: ['*.jar']) compile 'com.android.support:appcompat-v7:25.0.1' // Required——JUnit 4框架testCompile ' JUnit: JUnit:4.12' testCompile 'org.mockito:mockito-core:1.10.19'}
要为NumberAdder编写Junit + Mockito测试,请在文件夹中创建文件NumberAdderTest.java
Src /test/java/com/testsinandroid带有以下内容
包com.testsinandroid;进口com.testsinandroid.MainActivity;进口com.testsinandroid.NumberAdder;进口org.junit.测试;进口静态org.junit.断言.assertFalse;进口静态org.junit.断言.assertTrue;进口静态org.5.5.验证;进口静态org.5.5.*;进口org.junit.测试;进口org.junit.跑步者.RunWith;进口org.5.模拟;进口org.5.跑步者.MockitoJUnitRunner;@RunWith(MockitoJUnitRunner.类)公共类NumberAdderTest{@MockMainActivitymMockMainActivity;@Test公共无效testIsNumberValid(){/ /设置/ /测试NumberAddernumberAdder=新NumberAdder(mMockMainActivity);断言(numberAdder.isNumberValid(55.0));}@Test公共无效testIsNumberNotValid(){/ /设置/ /测试NumberAddernumberAdder=新NumberAdder(mMockMainActivity);assertFalse(numberAdder.isNumberValid(-55.0));}@Test公共无效testPerformAddition(){/ /设置当(mMockMainActivity.getFirstNumber()).thenReturn(10.0);当(mMockMainActivity.getSecondNumber()).thenReturn(11.0);/ /测试NumberAddernumberAdder=新NumberAdder(mMockMainActivity);numberAdder.performAddition();/ /验证验证(mMockMainActivity).setAdditionResult(21.0);}}
上面的代码创建了三个测试,它们使用@Test注释进行了注释。测试使用MockitoJUnitRunner运行。这个运行器为每个带@Mock注释的字段注入一个模拟对象。MainActivity在上面的测试中被模拟。在前两个测试中,我们根据函数返回的值进行断言。在第三个测试中,我们设置了调用getFirstNumber和getSecondNumber时返回的值。然后我们在mMockMainActivity上验证setAdditionResult方法是否具有正确的值。
一旦我们编写了这些本地JUnit测试,我们就可以使用gradle命令运行它们。如果所有测试都通过,构建将成功;如果没有通过,则构建失败。
/ gradlew测试。
使用Roboelectric编写测试
Robolectric是一个用于Android的单元测试框架。使用Roboelectric,您可以在工作站上的JVM上运行android单元测试。这对于在工作站上进行Android代码单元测试非常方便。如果没有通过测试,则构建可能失败。
要将Roboelectric添加到您的测试依赖项中,请按以下方式更新您的依赖项
dependencies {compile fileTree(dir: 'libs', include: ['*.jar']) compile 'com.android.support:appcompat-v7:25.0.1' //添加Junit和mockito作为测试依赖项testCompile ' Junit: Junit:4.12' testCompile 'org.mockito:mockito-core:1.10.19' //对于Roboelectric testCompile "org.robolectric:robolectric:3.0"}
一旦我们添加了依赖项,我们就可以为MainActivity添加以下测试
包com.testsinandroid;进口org.junit.测试;进口org.junit.之前;进口org.junit.跑步者.RunWith;进口org.robolectric.Robolectric;进口org.robolectric.注释.配置;进口安卓.操作系统.包;进口安卓.视图.视图;进口安卓.小部件.按钮;进口安卓.小部件.EditText;进口安卓.小部件.TextView;进口静态org.junit.断言.*;进口静态org.junit.断言.assertTrue;进口org.robolectric.RobolectricGradleTestRunner;@RunWith(RobolectricGradleTestRunner.类)@Config(常量=BuildConfig.类,sdk=21)公共类MainActivityTest{MainActivity活动;EditTextfirstNumber;EditTextsecondNumber;TextViewaddResult;按钮btnAdd;@Before公共无效设置(){活动=Robolectric.setupActivity(MainActivity.类);firstNumber=(EditText)活动.findViewById(R.id.txtNumber1);secondNumber=(EditText)活动.findViewById(R.id.txtNumber2);addResult=(TextView)活动.findViewById(R.id.txtResult);btnAdd=(按钮)活动.findViewById(R.id.btnAdd);}@Test公共无效testMainActivityAddition(){/ /设置firstNumber.setText(“12.2”);secondNumber.setText(“13.3”);/ /测试btnAdd.performClick();/ /验证assertequal(25.5,双.parseDouble(addResult.getText().toString()),0.0);}}
在上面的测试中,我们创建MainActivityTest。它是用RobolectricGradleTestRunner运行的。
然后我们使用Roboelectric API的“Robolectric”。setupActivity’ which instantiates the activity. It also calls its lifecycle methods like ‘OnCreate’, ‘onStart’ etc. Then we get the different view elements in the activity and set the values. Once the values are set we perform a click on the button. Then we finally verify that the result TextView has the appropriate value by using ‘assertEquals’.
如上面的例子所示,Roboelectric可以很容易地为Android代码编写单元测试。
编写Android Instrumentation测试
Android允许你编写检测单元测试。这些测试在实际的Android设备上运行。当你在实际设备上测试时,你不需要模拟Android类。测试android组件,比如activity等,用一个工具测试很容易。但问题是你需要一个实际的设备来运行测试。这些不能在您的工作站上运行它。
要添加插装,请按如下方式更新Gradle依赖项
dependencies {compile fileTree(dir: 'libs',包括:['*.jar']) compile 'com.android.support:appcompat-v7:25.0.1' //添加Junit和mockito作为测试依赖项testCompile ' Junit: Junit:4.12' testCompile 'org.mockito:mockito-core:1.10.19' //对于Roboelectric testCompile "org.robolectric:robolectric:3.0" //对于仪器测试androidTestCompile 'com.android.support:support-annotations:25.0.1' androidTestCompile 'com.android.support: runner:0.5' androidTestCompile 'com.android.support: runner:0.5' androidTestCompile 'com.android.support: rules:0.5'}
要为“MainActivity”编写一个插入测试,请创建MainActivityIntrumentationTest.java文件。文件应该在文件夹中
src/androidTest/java/com/testsinandroid带有以下内容
包com.testsinandroid;进口安卓.应用程序.仪表;进口安卓.测验.ActivityInstrumentationTestCase2;进口安卓.测验.TouchUtils;进口安卓.测验.ViewAsserts;进口安卓.视图.视图;进口安卓.操作系统.包;进口安卓.视图.视图;进口安卓.小部件.按钮;进口安卓.小部件.EditText;进口安卓.小部件.TextView;进口静态org.junit.断言.*;进口安卓.测验.UiThreadTest;公共类MainActivityIntrumentationTest扩展ActivityInstrumentationTestCase2<MainActivity>{MainActivity活动;EditTextfirstNumber;EditTextsecondNumber;TextViewaddResult;按钮btnAdd;公共MainActivityIntrumentationTest(){超级(MainActivity.类);}@Override受保护的无效设置()抛出异常{超级.设置();setActivityInitialTouchMode(真正的);活动=getActivity();firstNumber=(EditText)活动.findViewById(R.id.txtNumber1);secondNumber=(EditText)活动.findViewById(R.id.txtNumber2);addResult=(TextView)活动.findViewById(R.id.txtResult);btnAdd=(按钮)活动.findViewById(R.id.btnAdd);}@UiThreadTest公共无效testMainActivityAddition(){/ /设置firstNumber.setText(“12.2”);secondNumber.setText(“13.3”);/ /测试btnAdd.performClick();/ /验证assertequal(25.5,双.parseDouble(addResult.getText().toString()),0.0);}}
在上面的代码中,我们的测试类继承自ActivityInstrumentationTestCase2。ActivityInstrumentationTestCase2允许我们为Activity编写测试。在这个类的构造函数中,我们应该传递测试中的活动(在我们的例子中是' MainActivity ')。然后我们重写' setUp '方法,在该方法中我们获得活动对象和活动的其他UI元素。然后我们编写一个类似于我们在前一节中编写的测试。测试有一个注释“@UiThreadTest”。这将使这个测试在UI线程上运行,因为我们在测试中有一些UI操作。
使用命令连接设备后,可以运行仪表测试
。/ gradlew connectedCheck
结论
在本文中,我们已经看到了为Android代码编写单元测试的多种方法。根据项目的需要,您可以在项目中使用上述一种或多种类型的测试。自动化单元测试有很多长期的好处。它们应该作为开发工作本身的一部分来考虑和评估。上面描述的框架有助于为你的android应用程序编写单元测试。它们为你做了大部分繁重的工作,所以你可以专注于测试。所以,在你的下一个Android应用程序中编写单元测试吧。