android 交互式单测

在android开发中,页面显示,交互部分,经常遇到一些情况,如手势操作,UI在特定环境下的显示,交互等等。

如何判断这些部分是否编码正确?

通常的办法是运行程序,直接看,操作。用实践来检验真理。简单,易行。


但是,这样在一些情况下是比较麻烦的,如上下文环境准备麻烦等等。

这里有一种简单的测试办法,用单元测试。

不过这里说的测试不是通常的自动化测试,而是一种交互式测试,直接显示页面,人工判断显示正确,操作正确等。


1,测试activity。在特定的数据环境下,页面显示是否正确。

这里举一个例子来说明:微信通讯录tab, “新的朋友”处的显示。

此处没有未读的“新的朋友”,有一条未读的记录,有多条未读的记录显示的情况是不一样的。

具体规则是:

没有未读,图片显示默认icon, 文字显示"新的朋友"

有一条未读,图片显示对方头像,文字为两行,显示对方姓名,邀请文字。最右边还有一个红色的未读图标。

有多条未读,显示对方的头像,最多显示4个,右边 显示数量。


//主页面大体结构

public class MainActivity extends Activity{

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        init();
        getDataAndBindView();
    }
    
    private void init(){
        //初始化控件
    }
    
    private void getDataAndBindView(){
        //这里假定是从数据库中获取数据
    }
    
}

//测试代码大体结构

public class TestMainActivity extends ActivityInstrumentationTestCase2<MainActivity>{

    private CountDownLatch countDownLatch = new CountDownLatch(1);

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



    public void testNewContactOnEmpty() throws InterruptedException {
        //1.初始化数据源,放入假数据。
        //2.显示页面
        MainActivity activity = getActivity();
        //3.页面等待。并设置点击左上角的返回按钮后停止等待。
        activity.findViewById(R.id.back).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                countDownLatch.countDown();
            }
        });
        countDownLatch.await();

    }

    public void testNewContactOnOne(){

    }

    public void testNewContactOnThree(){

    }

    public void testNewContactOnFive(){

    }
}

测试方法,可以在IDE中选择单个运行,来检验有效性。

在 getActivity()  方法调用后,手机上会显示测试中的Activity。

Activity会获取数据源中的数据(假数据),根据数据不同来显示不同的UI。

为什么要加锁来停住测试方法呢?

因为测试方法运行完,意味着此单测的完成,页面会关闭。不加锁的话,就会看到页面一闪而过。

所以,通过锁让测试方法等待,这样就有足够的时间来用你那勤劳的双手,像素双眼来检测是否正确。

检测完成后,点击页面左上角的返回,释放锁,测试方法结束。


因为需要你手动检测,所以叫她 交互式单元测试。不能自动化。千万别与自动化测试一起测,如加@SmallTest什么的。

当然,这个例子也是可以用自动化测试来搞定的,如assert 文字显示 assert 图片显示 等。


交互式测试有它的缺点,不能自动化。

也有它的优点,在开发中,一目了然的知道所有情况下的正确性,复杂UI交互时,在特定数据显示特定UI等等情况,能够大大缩短开发周期。


上面讲了activity的交互式单测,下面讲View的单元测试

2,测试View。在特定的数据环境下,View显示是否正确

这里举一个例子来说明: 锁屏时来电的滑动解锁。

锁屏时来电,下方会有滑动解锁的区域,点击接听按钮向右滑动的时候,整个背景会跟着缩短。

滑动到最右侧放开,会接听电话,否则会退回到原始状态。


//view 代码

public class AnswerCallBySlideView extends RelativeLayout{

    private static final String TAG = "AnswerCallBySlideView";

    private View vgDescription , vBtn , vgSlideArea;
    private SlideListener slideListener;

    public AnswerCallBySlideView(Context context) {
        super(context);
        init();
    }

    public AnswerCallBySlideView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public AnswerCallBySlideView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    private void init(){
        inflate(getContext() , R.layout.view_slide_answer_call , this);
        vgSlideArea = findViewById(R.id.slide_area);;
        vBtn = findViewById(R.id.btn);
        vgDescription = findViewById(R.id.description_ll);
        vBtn.setOnTouchListener(slideTouchListener);
    }

    private OnTouchListener slideTouchListener = new OnTouchListener() {
        private int maxWidth , minWidth;
        private float startX;
        private float diff;
        private int error = 10;

        @Override
        public boolean onTouch(View v, MotionEvent event) {
            switch (event.getActionMasked()){
                case MotionEvent.ACTION_DOWN:
                    maxWidth = vgSlideArea.getWidth();
                    minWidth = vBtn.getWidth() + vgSlideArea.getPaddingLeft()+vgSlideArea.getPaddingRight();
                    vgSlideArea.setMinimumWidth(minWidth);
                    startX = event.getRawX();
                    vgDescription.setVisibility(View.GONE);

                    LogUtil.i(TAG , "onTouch() down maxWidth="+maxWidth +",minWidth="+minWidth);
                    break;
                case MotionEvent.ACTION_MOVE:
                    float curX = event.getRawX();
                    diff = curX - startX;
                    int newWidth = (int)(maxWidth-diff);
                    if(newWidth < minWidth){
                        newWidth = minWidth;
                    }
                    setWidth(newWidth);
                    LogUtil.i(TAG , "onTouch() move diff="+diff);

                    break;

                case MotionEvent.ACTION_UP:
                    curX = event.getRawX();
                    diff = curX - startX;
                    if(maxWidth <= minWidth + diff + error){
                        notifySlideSuccess();
                    }else{
                        restore();
                    }

                    LogUtil.i(TAG , "onTouch() up ");
                    break;
                case MotionEvent.ACTION_CANCEL:
                    restore();
                    LogUtil.i(TAG , "onTouch() cancel ");

                    break;
            }
            return true;
        }
    };

    private void setWidth(int width){
        ViewGroup.LayoutParams lp = vgSlideArea.getLayoutParams();
        lp.width = width;
        vgSlideArea.setLayoutParams(lp);
    }

    private void restore(){
        vgDescription.setVisibility(View.VISIBLE);
        ViewGroup.LayoutParams lp = vgSlideArea.getLayoutParams();
        lp.width = ViewGroup.LayoutParams.MATCH_PARENT;
        vgSlideArea.setLayoutParams(lp);
    }

    private void notifySlideSuccess(){
        LogUtil.i(TAG , "notifySlideSuccess()");
        if(slideListener != null){
            slideListener.onSlideSuccess();
        }
    }

    public interface SlideListener{
        public void onSlideSuccess();
    }

    public void setSlideListener(SlideListener slideListener) {
        this.slideListener = slideListener;
    }
}
先说明一下,这个不是源码,是我自己写的一段代码。

监听View的ontouch事件,来设定底部条的样子,当手指up时,通知成功,或者复原UI。


View要展示,需要放到一个Activitity中才行,所以写了一个测试View用的Activitiy。

package bj.lize.uitest;

import android.app.Activity;
import android.os.Bundle;
import android.view.ViewGroup;
import android.widget.LinearLayout;

import java.util.concurrent.CountDownLatch;

/**
 * Created by lize on 2014/12/1.
 */
public class <span style="font-family: Arial, Helvetica, sans-serif;">TestViewActivity </span>extends Activity{

    private CountDownLatch countDownLatch;
    public LinearLayout vgContent;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        countDownLatch = new CountDownLatch(1);
        vgContent = new LinearLayout(this);
        vgContent.setOrientation(LinearLayout.VERTICAL);
        vgContent.setBackgroundColor(0x000000);
        setContentView(vgContent, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
    }

    @Override
    public void onBackPressed() {
//        super.onBackPressed();
        unlock();
    }

    public void lock(){
        try {
            countDownLatch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public void unlock(){
        countDownLatch.countDown();
    }

    public LinearLayout getContent() {
        return vgContent;
    }
}

很简单的一个Activity,顶级View是一个纵向的LinearLayout, 测试的时候向它里面放入待测试View。

提供了lock()  unlock() 方法


测试代码。

package bj.lize.uitest;

import android.test.ActivityInstrumentationTestCase2;

/**
 * Created by lize on 2014/12/14.
 */
public class TestAnswerCallBySlideView extends ActivityInstrumentationTestCase2<TestViewActivity>{
    public TestAnswerCallBySlideView() {
        super(TestViewActivity.class);
    }

    public void testUI(){
        getActivity().runOnUiThread(new Runnable() {
            @Override
            public void run() {
                getActivity().getContent().addView(new AnswerCallBySlideView(getActivity()));
            }
        });
        getActivity().lock();
    }

}
执行了这个测试代码,就发现你的View出现在屏幕上了,你可以用你勤劳的双手双眼来确认它的正确性了。


之所以要用 getActivity().runOnUiThread  是因为测试方法并不是UI线程,如果直接执行 addView 操作,就会抛出异常。


到这里,交互式测试就讲完了,方法很简单。用到合适的场景,还是很爽的。

目前我经常用到的一些场景:

  1. 手势操作,就是需要写onTouch  的那些地方。
  2. 复杂数据显示:

Listview 显示数据,listitem有多种显示类型

不同数据有不同的显示UI

等等

大家还有什么好的想法,好的应用场景可以告诉我。谢谢。








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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值