Android Studio进行单元测试


1.     什么是单元测试

单元测试(模块测试)是开发者编写的一小段代码,用于检验被测代码的一个很小的、很明确的功能是否正确。通常而言,一个单元测试是用于判断某个特定条件(或者场景)下某个特定函数的行为。例如,你可能把一个很大的值放入一个有序list 中去,然后确认该值出现在list 的尾部。或者,你可能会从字符串中删除匹配某种模式的字符,然后确认字符串确实不再包含这些字符了。

单元测试是由程序员自己来完成,最终受益的也是程序员自己。可以这么说,程序员有责任编写功能代码,同时也就有责任为自己的代码编写单元测试。执行单元测试,就是为了证明这段代码的行为和我们期望的一致。(引自于百度百科,其实我也不懂)

2.     InstrumentationTestCase

InstrumentationTestCase是Android 中进行测试的组合类中的基础类,在junit.framework包里,继承于TestCase,可以便捷的进行一些简单的测试。

已知直接子类

ActivityTestCase,ProviderTestCase<Textends ContentProvider>, SingleLaunchActivityTestCase<T extendsActivity>, SyncBaseInstrumentation

已知间接子类

ActivityInstrumentationTestCase<Textends Activity>, ActivityInstrumentationTestCase2<T extendsActivity>, ActivityUnitTestCase<T extends Activity>

在日常编程中,测试类习惯放于androidTest包中,命名以Test结尾,以便于与开发类进行区分。如图1-1

 

图1-1

新建类SimpleTest进行测试如下:

public class SimpleTest extends InstrumentationTestCase {
    @MediumTest
    public void testSimple()throws Exception 
{
        try {
            Thread.sleep(10000);//试试会不会ANR
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        assertEquals(2, 2);//比较功能,比较2是否等于2,若是,继续运行,如不是则抛出异常,详见附录1
    }
}


在测试类中,当方法已test开头,在运行中将自动调用,换言之,测试方法必须已test开头

运行:选中当前类,右键-->Run “SimpleTest”

运行成功如图1-2


 

图1-2

如改为assertEquals(1,2);则运行失败如图1-3

图1-3

 

3.     ActivityUnitTestCase<Textends Activity>

ActivityUnitTestCase是ActivityTestCase的子类,添加了一些接口,是InstrumentationTestCase的孙子类,它是针对于Activity封装的类,以方便于开发人员对Activity中的代码进行测试。

开发人员是使用ActivityUnitTestCase时必须要重写构造方法,并在构造方法中调用super(T extends Activity),并将索要测试的Activity的class对象传入其中,除此之外,还要重写父类的setUp方法。

在ActivityUnitTestCase中,可以直接调用getActivity方法来获取Activity的对象,并可以获得Activity中相应权限的方法和属性,并加以测试调用。代码如下:

 

public class LoginActivityTest extends ActivityUnitTestCase<LoginActivity> {
    private Intent mLoginIntent;

    public LoginActivityTest() {
        super(LoginActivity.class);
    }

    @Override
    protected void setUp() throws Exception {
        super.setUp();
        mLoginIntent = new Intent(getInstrumentation().getTargetContext(), LoginActivity.class);
    }

    /**
     * 验证Button上的文字是否与目标一致
     */
    @MediumTest
    public void testAa()throws Exception 
 {
        startActivity(mLoginIntent, null, null);//获取Activity的对象首先要启动它
        final Button loginButton = (Button) getActivity().findViewById(R.id.btn_login);
        assertEquals("Unexpected button ladel text", "login", loginButton.getText());
        int i = ((LoginActivity) getActivity()).getCount();//getCount()为LoginActivity的一个方法,可以对其加以验证

    }

    /**
     * 测试对Button进行20次点击后,显示文字是否与目标一致
     */
    @MediumTest
    public void testOnClick throws Exception 
 () {
        startActivity(mLoginIntent, null, null);//在每个test方法中都要重新启动activity
        final Button loginButton = (Button)getActivity().findViewById(R.id.btn_login);
        for (int i = 0; i < 20; i++){
            loginButton.performClick();
        }
        assertEquals("Unexpected button ladel text", "login", loginButton.getText());
    }
}
 
4.     ActivityInstrumentationTestCase2<T extends Activity >

ActivityInstrumentationTestCase2是ActivityTestCase的子类,该类与上述两个类的最明显的区别就是该类在运行时会有界面显示,但是在整个测试流程结束时会将activity关闭,在这里模拟的点击事件将有TouchUtils来实现,通过该类可以进行点击、长按、滑动等操作。
 
public class MainActivityFunctionalTest extends ActivityInstrumentationTestCase2<MainActivity> {
    private MainActivityactivity;

    public MainActivityFunctionalTest(){
        super(MainActivity.class);
    }

    @Override
    protected void setUp() throws Exception {
        super.setUp();
        setActivityInitialTouchMode(false);
        activity =getActivity();
    }

    public void testStartLoginActivity()throws Exception {


        Button view = (Button) activity.findViewById(R.id.btn_login);

        for (int i = 0; i < 1; i++){
            Thread.sleep(1000);
            TouchUtils.clickView(this, view);//模拟点击事件
        }

        // 添加要启动的Activity到Monitor
        Instrumentation.ActivityMonitor monitor =
                getInstrumentation().
                       addMonitor(LoginActivity.class.getName(), null, false);
        TouchUtils.clickView(this, activity.findViewById(R.id.btn2));//通过点击事件启动LoginActivity
        // 等待两秒时间启动LoginActivity
        LoginActivity startedActivity =(LoginActivity) monitor
               .waitForActivityWithTimeout(2000);
        //启动成功不为空,失败为空
        assertNotNull(startedActivity);
        //LoginActivity里的TextView
        TextView textView = (TextView)startedActivity.findViewById(R.id.btn_login);
        for (int i = 0; i < 10; i++){
            Thread.sleep(1000);
            TouchUtils.clickView(this, textView);
        }
        //检测textview是否在启动的activity中
        ViewAsserts.assertOnScreen(startedActivity.getWindow().getDecorView(),
                textView);
        assertEquals("Text incorrect", "login", textView.getText().toString());
        // 模拟点击back键
        this.sendKeys(KeyEvent.KEYCODE_BACK);
        TouchUtils.clickView(this, view);
    }
}


 

5.   总结

我们编写代码时,一定会反复调试保证它能够编译通过。如果是编译没有通过的代码,没有任何人会愿意交付给自己的老板。但代码通过编译,只是说明了它的语法正确;我们却无法保证它的语义也一定正确,没有任何人可以轻易承诺这段代码的行为一定是正确的。

幸运的是,单元测试会为我们的承诺做保证。编写单元测试就是用来验证这段代码的行为是否与我们期望的一致。有了单元测试,我们可以自信的交付自己的代码,而没有任何的后顾之忧。

由谁测试?单元测试与其他测试不同,单元测试可看作是编码工作的一部分,应该由程序员完成,也就是说,经过了单元测试的代码才是已完成的代码,提交产品代码时也要同时提交测试代码。测试部门可以作一定程度的审核。

 

由于作者水平有限,以上仅作为参考了解。

6.   附录1

在静态类junit.framework.Assert 中存在以下几个方法

1.assertEquals()方法,用来查看对象中存的值是否是期待的值,与字符串比较中使用的equals()方法类似;

 

2.assertFalse()和assertTrue()方法,用来查看变量是是否为false或true,如果assertFalse()查看的变量的值是false则测试成功,如果是true则失败,assertTrue()与之相反。

 

3.assertSame()和assertNotSame()方法,用来比较两个对象的引用是否相等和不相等,类似于通过“==”和“!=”比较两个对象;

 

4.assertNull()和assertNotNull()方法,用来查看对象是否为空和不为空。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值