安卓基础干货(二):安卓测试以及解析

1.测试的相关概念

1、根据是否知道源代码分类:

黑盒测试: a - b - c  边值测试
白盒测试: 根据源代码写测试方法 或者 测试用例;

2、根据测试的粒度分类:

方法测试:写完一个方法后就测试
单元测试:测试一个能够独立运行的业务逻辑单元;
集成测试:整体测试项目 联调
系统测试:对整个系统进行测试

3、根据测试的暴力程度:

1、冒烟测试:高频次的点击软件
2、压力测试:使用测试工具:LoadRunner、Jmeter

2.单元测试

Junit

01_Junit单元测试 does not specify a android.test.InstrumentationTestRunner instrumentation or does not declare uses-library android.test.runner in its AndroidManifest.xml

单元测试的步骤:

1、写一个业务类,写一个业务方法:

public class CalcService {

public static int add(int x,int y){

    return x+y;
}

}

2、写一个测试类,写一个测试方法,用来测试业务方法

public class CalcServiceTest extends AndroidTestCase{

public void testAdd(){
    int result = CalcService.add(4, 5);
    assertEquals(9, result);
    }

}

3、在清单文件中添加测试需要的包

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.itheima.junit"
android:versionCode="1"
android:versionName="1.0" >

<!-- 添加指令集,添加到manifest节点的里面,指令集会把应用程序部署到模拟器上运行 -->

<instrumentation android:name="android.test.InstrumentationTestRunner" android:targetPackage="com.itheima.junit"></instrumentation>

<application
    android:allowBackup="true"
    android:icon="@drawable/ic_launcher"
    android:label="@string/app_name"
    android:theme="@style/AppTheme" >

    <!-- 添加JUnit的测试包 ,添加到application节点的里面-->

    <uses-library android:name="android.test.runner"/>

    ....
</application>

</manifest>

3.Logcat日志工具的使用

日志的等级:

error:最高等级,错误信息,红色

warn:比较高,警告信息,橙色

debug:较高,调试信息,蓝色

info:一般,一般信息,绿色

verbose:一般,所有信息,黑色

4.把数据存储到文件

Android应用程序存储数据的方式:

1、保存到文件
2、SQLite数据库
3、内容提供者
4、sharedproferrences保存数据
5、网络

/data/data/应用包名/info.txt

5.从文件中读取数据并显示到界面上

(1)把文件保存到当前应用程序的目录下的步骤:

1、创建一个文件,目录/data/data/<包名>/文件名
2、创建一个文件输出流,把数据写到文件上
3、关闭输出流。
代码:
            //保存数据
            File file = new File("/data/data/com.itheima.login/info.txt");
            FileOutputStream fos = new FileOutputStream(file);
            String info = qq + "##"+ pwd;
            fos.write(info.getBytes());

            fos.close();
            Toast.makeText(this, "保存数据成功", 0).show();

(2)读取文件中的数据,并显示到界面上

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

    et_qq = (EditText) findViewById(R.id.et_qq);

    et_pwd = (EditText) findViewById(R.id.et_pwd);

    cb = (CheckBox) findViewById(R.id.cb);

    //读取文件中的数据,并显示到界面上
    Map<String,String> map = readInfo(this);
    if(map != null){
        et_qq.setText(map.get("qq"));

        et_pwd.setText(map.get("pwd"));
    }

}

 /**
 * 读取文件中的数据
 * @param ctx
 * @return
 */
public Map<String,String> readInfo(Context ctx){
    String qq = "";
    String pwd = "";
    Map<String,String> map = new HashMap<String,String>();
    try {
        File file = new File("/data/data/com.itheima.login/files/info.txt");
        FileReader fr = new FileReader(file);
        BufferedReader br = new BufferedReader(fr);
        String info = br.readLine();

        String[] array = info.split("##");
        qq = array[0];
        pwd = array[1];

        map.put("qq", qq);

        map.put("pwd", pwd);
        return map;

    } catch (Exception e) {
        e.printStackTrace();
        return null;
    }

}
    

6.存储到SD卡(重点)

异常信息:
09-21 23:25:32.068: W/System.err(24718): java.io.FileNotFoundException: /storage/sdcard/info.txt: open failed: EACCES (Permission denied)

步骤:

1、  在SD卡上创建一个文件,

2、创建一个输出流往sd卡上写数据
String data = "dsfdsae";

        File file = new File(Environment.getExternalStorageDirectory(), "info.txt");

        FileOutputStream fos = new FileOutputStream(file);
        fos.write(data.getBytes());

        fos.close();

3、在清单文件中添加访问SD卡的权限
 <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

7.获取SD的大小及可用空间

//获得sd卡的目录对象
    File file = Environment.getExternalStorageDirectory();

    //获得sd卡总空间的大小
    long total =  file.getTotalSpace();

    //转换数据大小的数据单位
    String totalSize = Formatter.formatFileSize(this, total);
    //获得sd卡剩余空间的大小
    long usable = file.getUsableSpace();

    String usableSize = Formatter.formatFileSize(this, usable);

    tv.setText(usableSize+"/"+totalSize);

8.文件的权限概念

文件的4种操作模式:
Context.MODE_PRIVATE:为默认操作模式,代表该文件是私有数据,只能被应用本身访问,在该模式下,写入的内容会覆盖原文件的内容,如果想把新写入的内容追加到原文件中。可以使用Context.MODE_APPEND

Context.MODE_APPEND:模式会检查文件是否存在,存在就往文件追加内容,否则就创建新文件。
Context.MODE_WORLD_READABLE和Context.MODE_WORLD_WRITEABLE用来控制其他应用是否有权限读写该文件。

MODE_WORLD_READABLE:表示当前文件可以被其他应用读取;MODE_WORLD_WRITEABLE:表示当前文件可以被其他应用写入。
如果希望文件被其他应用读和写,可以传入:
  openFileOutput("itcast.txt", Context.MODE_WORLD_READABLE +             Context.MODE_WORLD_WRITEABLE);

android有一套自己的安全模型,当应用程序(.apk)在安装时系统就会分配给他一个userid,当该应用要去访问其他资源比如文件的时候,就需要userid匹配。默认情况下,任何应用创建的文件,sharedpreferences,数据库都应该是私有的(位于/data/data/<package name>/files),其他程序无法访问。除非在创建时指定了Context.MODE_WORLD_READABLE或者Context.MODE_WORLD_WRITEABLE ,只有这样其他程序才能正确访问。

9.SharedPreferences第二种存储方式(重点)

 主要用于

(1)往SharedPreferences保存数据

 public void save(View v){

    String data = et.getText().toString().trim();
    if(TextUtils.isEmpty(data)){
        Toast.makeText(this, "请输入数据", 0).show();
        return;
    }else{

        //得到一个SharedPreferences
        SharedPreferences sp = this.getSharedPreferences("info", Context.MODE_PRIVATE);
        //SharedPreferences提供了一个编辑器,帮助我们保存数据
        Editor editor = sp.edit();

        editor.putString("data", data);

        //把数据保存到SharedPreferences中
        editor.commit();

    }
}

(2)从SharedPreferences读取数据
public String readData(){

    String data;
    try {
        //得到一个SharedPreferences
        SharedPreferences sp = this.getSharedPreferences("info", Context.MODE_PRIVATE);
        //根据参数名称得到数据
        data = sp.getString("data", null);
    } catch (Exception e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
        data = "";
    }

    return data;

}
 

10.使用序列化器生成一个xml文件

//1,初始化一个xml文件的序列化器
        XmlSerializer serializer = Xml.newSerializer();
        //2.初始化序列器参数
        File file = new File(Environment.getExternalStorageDirectory(),"backup.xml");
        FileOutputStream fos = new FileOutputStream(file);
        serializer.setOutput(fos, "UTF-8");
        //3.开始写xml文件.
        serializer.startDocument("UTF-8", true);
        serializer.startTag(null, "smss");
        for(SmsInfo info : smsInfos){
           //开始写sms节点
            serializer.startTag(null, "sms");
            //开始写body节点
            serializer.startTag(null, "body");
            serializer.text(info.getBody());
            //body节点结束
            serializer.endTag(null, "body"); 

            //开始写address节点
            serializer.startTag(null, "address");
            serializer.text(info.getAddress());
            serializer.endTag(null, "address");

            //开始写data节点
            serializer.startTag(null, "date");
            serializer.text(info.getDate()+"");
            serializer.endTag(null, "date");
            // sms节点结束
            serializer.endTag(null, "sms");
        }
        //smss根节点结束
        serializer.endTag(null, "smss");
        //xml 结束
        serializer.endDocument();
        fos.close();

        Toast.makeText(this, "备份短信成功", 0).show();
    } catch (Exception e) {
        e.printStackTrace();
        Toast.makeText(this, "备份短信失败", 0).show();
    }

11.使用pull解析xml格式的数据 (重要)

public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
   // 设置activity显示的布局
    setContentView(R.layout.activity_main);
    TextView tv_info = (TextView) findViewById(R.id.tv_info);
    StringBuilder sb = new StringBuilder();
    try {
        //获取我们解析出来的天气信息
        List<Channel> channels = WeatherService.getAllWeatherInfos(getClass().getClassLoader().getResourceAsStream("weather.xml"));
        for(Channel channel : channels){
            sb.append(channel.toString());
            sb.append("\n");
        }
        //把解析出来的天气信息设置到textview上
        tv_info.setText(sb.toString());

    } catch (Exception e) {
        e.printStackTrace();
        Toast.makeText(this, "解析天气信息失败", 0).show();
    }

}

}

  public class WeatherService {
/**
 * 解析服务器返回的数据 获取天气信息
 * @param is 服务器返回的包含天气信息的流 (xml)
 * @return
 */
public static List<Channel> getAllWeatherInfos(InputStream is) throws Exception{
    List<Channel> channels = null;
    Channel channel = null;
    //1.获取xml解析器
    XmlPullParser parser = Xml.newPullParser();
    //2.设置xml解析器的参数
    parser.setInput(is, "utf-8");
    //3.开始解析xml文件.

    int type = parser.getEventType();// 获取当前的事件的类型
    while (type!=XmlPullParser.END_DOCUMENT){ //需要让pull解析器解析到文件的末尾
        switch (type) {
        case XmlPullParser.START_TAG:
            if("weather".equals(parser.getName())){//总的开始节点
                channels = new ArrayList<Channel>(); //初始化集合
            }else if("channel".equals(parser.getName())){//某个城市的信息开始了.
                channel = new Channel();
                //获取到id的属性值
                String id = parser.getAttributeValue(0);
                channel.setId(Integer.parseInt(id));
                //解析city节点
            }else if("city".equals(parser.getName())){
                String city = parser.nextText();
                channel.setCity(city);
                //解析温度节点
            }else if("temp".equals(parser.getName())){
                String temp = parser.nextText();
                channel.setTemp(temp);
                //解析风力节点
            }else if("wind".equals(parser.getName())){
                String wind = parser.nextText();
                channel.setWind(wind);
                 //解析pm250节点
            }else if("pm250".equals(parser.getName())){
                String pm250 = parser.nextText();
                channel.setPm250(Integer.parseInt(pm250));
            }
            break;
        //判断xml的结束节点
        case XmlPullParser.END_TAG:
            if("channel".equals(parser.getName())){
                //把解析的内容加入到集合中
                channels.add(channel);
                channel = null;
            }
            break;
        }

        type = parser.next();
    }

    is.close();
    return channels;//把所有的频道的集合返回回去
 }
}

原文地址:https://www.cnblogs.com/fanchcho/p/9233851.html

时间: 2024-08-26 06:26:01

安卓基础干货(二):安卓测试以及解析的相关文章

星云精准测试对安卓底层驱动代码的测试案例分析

Android原生底层驱动应用面极广,但一直没有很好的办法进行质量追踪.本文借助星云精准测试的高可靠性的测试技术手段,针对Android原生底层驱动进行分析.插桩.编译.采集数据.数据分析等,逐步讲解精准测试是如何实现android原生底层驱动的对接. 在本文中,我们可以清晰地查看到如何进行技术对接的每一步,比如如何使用星云精准测试进行代码插桩.实现测试用例与采集底层驱动运行代码的数据追溯.对最终采集的数据进行一系列分析等. 一.安卓源码精准测试流程概述 经分析android源码的编译主要依靠A

安卓基础

1.  Service 服务 (是一个没有用户界面的在后台运行执行耗时操作的应用组件) 第一种方式: (startService 未绑定, 当程序退出,若没有停止服务则会继续在后台运行) //继承 Service public class MyService extends Service { private String tag = "MyService"; @Override public IBinder onBind(Intent intent) { // TODO Auto-g

安卓自定义控件(二)BitmapShader、ShapeDrawable、Shape

第一篇博客中,我已经对常用的一些方法做了汇总,这篇文章主要介绍BitmapShader位图渲染.ComposeShader组合渲染,然后看看Xfermode如何实际应用.不过本文还是只重写onDraw一个方法,工欲善其事必先利其器嘛,一个方法一个方法地学,先了解每个对象是干什么的. ViewHelper(View处理常用方法封装) 安卓自定义控件(一)Canvas.Paint.Shader 安卓自定义控件(二)BitmapShader.ShapeDrawable.Shape 带边框的椭圆形Ima

HttpDNS的坑以及一个针对安卓不太完善的测试方案

背景:单位因为域名劫持(具体表象是某个地区的用户ping不通域名或者因为DNS解析的ip跨网段导致访问速度很慢)需要运维经常去定位,于是提出了httpDNS方案. 想法是美好的,现实是残酷的.没引入这个机制还好,引入后问题更多. 坑1: 因为DNSPod收费,为了节省费用,我们采用了优先使用本地DNS的策略,服务器出现非200错误码,就切HttpDNS.结果服务器一个接口出现问题,导致大批量流量走HttpDNS. 解决方案:非502和非200返回码才走HttpDNS 坑2:在测试环境测试OK,在

安卓基础01

安卓基础01 SDK System images 这是在创建模拟器时需要的system image,也就是在创建模拟器时CPU/ABI项需要选择的,下载并解压后,将解压出的整个文件夹复制或者移动到 your sdk 路径/system-images文件夹下即可, 如果没有 system-images目录就先 创建此文件夹,然后打开SDK Manager,打开Tools(工 具)菜单选择Options(选项)菜单项打开Android SDK Manager Setting对话框,点击Clear C

回顾安卓基础

以前老张教c的时候说过:学的越多,总结的越少,就越好. 开始的时候不能理解,现在终于慢慢悟出了. 准备慢慢总结一下经常用到的安卓基础,算是重温一下美好记忆吧.个人博客记录个人心得,希望开心自己的同时也能够帮助别人. 从布局开始吧: 总结相对布局: 1.父控件与子控件的关系(alignParentXXX) 2.控件与指定控件的位置关系.(above,below,toRightOf,toLeftOf) 3.控件与指定控件的对其关系(alignTop,alignBottom,alignLeft,ali

安卓基础开发-短信发送器

一个安卓基础开发小案例,短信发送器: 代码演示图: 布局文件: activity_main.xml <span style="font-family:Comic Sans MS;font-size:14px;"><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/

安卓开发技巧二:自定义日志工具类XLog的实现

我们在开发过程中,打印日志是必不可少的一个调试环节,然而,直接使用系统自带的Log日志类,并不能满足我们实际项目的需求:假如我们现在在开发一款比较大的项目,用到打印日志的地方肯定特别多,等到真正上线的时候,我们是不希望日志依旧能够打印出的,原因很简单,不仅多少有些影响效率,更有可能导致信息的泄露,所以我们就需要把所有的日志打印语句全部取消掉,难道我们真的一个一个的去删除这些打印日志的语句吗?项目那么大,就是想删除,也得耗费大量的时间和精力!大家不用怕,笔者这就给大家带来一款控制线上版本和线下版本

安卓基础之主题/样式

安卓基础之主题/样式 样式:一般作用在控件上,使多个控件拥有相同风格 主题:一般作用清单文件的activity或application结点下 样式Style的使用 系统自动在app/res/values/路径下建立style.xml文件,用来添加,引用Style,因此一般情况下我们在这个文件中定义自己的Style就可以了. 定义好一个style后,我们就可以在定义控件时调用这个Style 如果我们要在界面中定义样式相似的多个组件,我们可以把控件中的相同的属性抽出来,自定义Style,定义控件时引