Monkey测试与StrictMode

Monkey测试

1.Monkey测试的目的

Monkey测试是Android平台自动化测试的一种手段,通过Monkey程序模拟用户触摸屏幕、滑动Trackball、按键等操作来对设备上的程序进行压力测试,检测程序多久的时间会发生异常。

2.Monkey测试的执行

通过adb命令开始执行monkey测试,monkey命令的基本格式为:C:\Users\zhenpu.zhang>adbshell monkey-pcom.android.deskclock-v -v -v-s 1000–throttle500 30000>F:\log\monkey_log.txt。这条命令中,-p代表一个包,即我们monkey测试的对象,一条命令可以有多个包,每添加一个包则需要一个-p,如 adb shell monkey –p 包1 –p 包2。com.android.deskclock 就是我们需要执行测试的对象。-v 代表返回结果的详尽程度,分为3级,分别是level 1 level 2 level 3,级别越高,返回的log会更详尽,1级为-v ,2级为-v –v,3级为 –v –v –v.180000 代表执行次数,根据实际测试需要来修改。-s<seed>伪随机数生成器的seed值,它影响伪随机事件的发生顺序,如果用相同的seed值再次执行Monkey,它将产生相同的事件序列。-throttle 500 代表间隔时间,即每次操作的时间间隔。为了更好的模拟用户操作,需要在每次操作之间增加时间间隔,单位是毫秒,此命令的含义就是增加500ms的时间间隔。>F:\log\monkey_log.txt表示monkey的日志将保存在F盘文件夹名为log的文件夹中,日志的文件名为monkey_log.txt。

3.Monkey测试结果

在运行Monkey命令时,遇到crash或者ANR(application not responding),Monkey就会停止运行,Monkey的测试结果可以在monkey_log.txt中看到,如果测试顺利执行完毕,log的最后一行会有Monkey finished,并且手机运行正常。通过多次并且不同设定下的Monkey测试才算它是一个稳定性和健壮性足够的程序。一般我们执行Monkey时,在3万次以内发生Crash的话就认为app是有问题的,要提交PR。MonkeyPR的规则如下,标题:在PR标题上加上Monkey。内容:主要包含自己执行的命令以及在多少次发生crash。其他:在PR上附上相关的Monkeylog以及手机单的后台log,app停止运行的照片也可以贴上。

StrictMode

StrictMode工具类主要用来帮助开发者发现代码中的一些不规范的问题,常用来检查在UI线程中对磁盘的读写与网络的访问,因为在UI线程中进行这样的操作会使得app的反应变得卡顿,有时甚至会弹出ANR对话框。

StrictMode 通过策略方式来让你自定义需要检查哪方面的问题。主要有两中策略,一个时线程方策略(ThreadPolicy),一个是VM方面的策略(VmPolicy)。ThreadPolicy 主要用于发现在UI线程中是否有读写磁盘的操作,是否有网络操作,以及检查UI线程中调用的自定义代码是否执行得比较慢。VmPolicy,主要用于发现内存问题,比如 Activity内存泄露, SQL 对象内存泄露, 资源未释放,能够限定某个类的最大对象数。

如何开启StrictMode

我们通常在 Activity 或者自定义的Application类中启动StrictMode,代码如下:

publicvoidonCreate() {

     if (DEVELOPER_MODE){

         StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()

                 .detectDiskReads()

                 .detectDiskWrites()

                 .detectNetwork()   // or .detectAll() for alldetectable problems

                 .penaltyLog()

                 .build());

         StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()

                 .detectLeakedSqlLiteObjects()

                 .detectLeakedClosableObjects()

                 .penaltyLog()

                 .penaltyDeath()

                 .build());

     }

     super.onCreate();

 }

注意:我们只需要在app的开发版本下使用 StrictMode,线上版本避免使用 StrictMode,随意需要通过诸如DEVELOPER_MODE这样的配置变量来进行控制。

至于具体的使用,可以通过下面的例子来展示。

publicclassActivitySimpleextendsActivity{
    @Override
    protectedvoidonCreate(BundlesavedInstanceState){
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        StrictMode.setThreadPolicy(newThreadPolicy.Builder()
                .detectAll()
                .penaltyDialog()//弹出违规提示对话框
                .penaltyLog()//在Logcat 中打印违规异常信息
                .build());
        this.testNetwork();
    }
    privatevoidtestNetwork(){
        try{
            URLurl=newURL("http://www.baidu.com");
            HttpURLConnectionconn=(HttpURLConnection)url.openConnection();
            conn.connect();
            BufferedReaderreader=newBufferedReader(newInputStreamReader(
                    conn.getInputStream()));
            Stringlines=null;
            StringBuffersb=newStringBuffer();
            while((lines=reader.readLine())!=null){
                sb.append(lines);
            }
        }catch(Exceptione){
            e.printStackTrace();
        }
    }
}

在这里例子中,我们在主线程(UI线程)中执行了网络请求,ThreadPolicy 策略中的 detectAll()方法 包含而来对这类违规操作的检查,同时我们通过penaltyDialog() 和 penaltyLog() 两个方法将违规信息提示给开发者。

StrictMode.ThreadPolicy.Builder的主要方法:

(1)dtectNetwork()用于检查UI线程中是否有网络访问请求。

(2)detectDiskReads()和detectDiskWrites()检查磁盘的读写。

(3)detectCustomSlowCalls()主要用于帮助开发者发现UI线程调用的那些方法执行得比较慢,要和 StrictMode.noteSlowCall 配合使用,StrictMode.noteSlowCall 只有通过 StrictMode.noteSlowCall用来标记“可能会”执行比较慢的方法,只有标记过的方法才能被检测到,日志中会记录方法的执行时间(比如 ~duration=2019 ms)。当然你也可以在其他线程中使用detectCustomSlowCalls(),但是没有什么实际意义,也看不到方法执行时间。

(4)penaltyDeath(),当触发违规条件时,直接Crash掉当前应用程序。

(5)penaltyDeathOnNetwork(),当触发网络违规时,Crash掉当前应用程序。

(6)penaltyDialog(),触发违规时,显示对违规信息对话框。

(7)penaltyFlashScreen(),会造成屏幕闪烁,不过一般的设备可能没有这个功能。

(8)penaltyDropBox(),将违规信息记录到 dropbox 系统日志目录中(/data/system/dropbox),你可以通过如下命令进行查看:

adb shell dumpsys dropbox dataappstrictmode  --print

(9)permitCustomSlowCalls()、permitDiskReads ()、permitDiskWrites()、permitNetwork: 如果你想关闭某一项检测,可以使用对应的permit*方法。

VMPolicy的常用方法:

(1)detectActivityLeaks() 用户检查 Activity 的内存泄露情况。

public class ActivityTestActivityLeaks extends Activity {

    private static boolean isStrictMode= false;

    @Override

    protected voidonCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_main);

        if(! isStrictMode){

            StrictMode.setVmPolicy(new VmPolicy.Builder()

            .detectActivityLeaks()

            .penaltyLog()

            .build());

            isStrictMode = true;

        }

        new Thread() {

              @Override

              public voidrun() {

                while (true){

                  SystemClock.sleep(1000);

                }

              }

        }.start();

    }

}

(2)detectLeakedClosableObjects()和detectLeakedSqlLiteObjects(),资源没有正确关闭时会触发。detectLeakedSqlLiteObjects() 和detectLeakedClosableObjects()的用法类似,只不过是用来检查SQLiteCursor 或者 其他 SQLite 对象是否被正确关闭。

public classMainActivityTestDetectLeakedClosableObjects extendsActivity {

    private static boolean isStrictMode= false;

    @Override

    protected voidonCreate(BundlesavedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_main);

        if(! isStrictMode){

            StrictMode.setVmPolicy(new VmPolicy.Builder()

            .detectLeakedClosableObjects()

            .penaltyLog()

            .build());

            isStrictMode = true;

        }

        File newxmlfile = newFile(Environment.getExternalStorageDirectory(),"aaa.txt");

        try {

            newxmlfile.createNewFile();

            FileWriter fw = newFileWriter(newxmlfile);

            fw.write("aaaaaaaaaaa");

            //fw.close(); 我们在这里故意没有关闭 fw

        } catch (IOExceptione) {

            e.printStackTrace();

        }

    }

}

(3)detectLeakedRegistrationObjects() 用来检查 BroadcastReceiver 或者 ServiceConnection 注册类对象是否被正确释放。

public class ActivityTestLeakedRegistrationObjects extends Activity {

    private TextView textView= null;

    private static boolean isStrictMode= false;

    private MyReceiverreceiver = null;

    @Override

    protected voidonCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_main);

        this.textView = (TextView)findViewById(R.id.text_view);

        this.textView.setText("In ActivityTestLeakedRegistrationObjects");

        if(! isStrictMode){

            StrictMode.setVmPolicy(new VmPolicy.Builder()

            .detectLeakedRegistrationObjects()

            .penaltyLog()

            .build());

            isStrictMode = true;

        }

        this.receiver = newMyReceiver(); 

        IntentFilter filter =new IntentFilter(); 

        filter.addAction("android.intent.action.MY_BROADCAST");

        registerReceiver(this.receiver, filter);

    }

    @Override

    protected voidonDestroy() {

        super.onDestroy();

    }

}

 

(4)setClassInstanceLimit(),设置某个类的同时处于内存中的实例上限,可以协助检查内存泄露。

public class ActivityTestObjectLimit extends Activity {

    private static classMyClass{}

    private static boolean isStrictMode= false;

    private staticList<MyClass> classList = new ArrayList<ActivityTestObjectLimit.MyClass>();

    @Override

    protected voidonCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_main);

 

        if(! isStrictMode){

            StrictMode.setVmPolicy(new VmPolicy.Builder()

            .setClassInstanceLimit(MyClass.class,2)

            .penaltyLog()

            .build());

            isStrictMode = true;

        }

        classList.add(new MyClass());

        classList.add(new MyClass());

        classList.add(new MyClass());

        classList.add(new MyClass());

        classList.add(new MyClass());

        classList.add(new MyClass());

        classList.add(new MyClass());

        classList.add(new MyClass());

    }

}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值