Android-UnitTest
来源:互联网 发布:如何评价李鸿章 知乎 编辑:程序博客网 时间:2024/05/18 18:55
Android单元测试
概述
现在国内很多开发人员都没有写单元测试的习惯,但写单元测试能减少很多不必要的麻烦。现在我们就从以下来介绍下单元测试。
一、什么是单元测试
- 单元测试是开发者编写的一小段代码,用于检验被测代码中的一个很明确的功能是否正确,其中,单元指的是测试的最小模块。通常而言,一个单元测试是用于判断某个特定条件(或者场景)下某个特定函数的行为。单元测试的代码不会被编译进入APK中。
二、单元测试目标函数
- 单元测试的目标函数即测试目标,主要有三种:
1) 有明确的返回值,验证函数的返回值是否符合预期结果。
2) 这个函数只改变其对象内部的一些属性或者状态,函数本身没有返回值,就验证它所改变的属性和状态。
3) 一些函数没有返回值,也没有直接改变哪个值的状态,这就需要验证其行为,比如点击事件。
既没有返回值,也没有改变状态,又没有触发行为的函数是不可测试的,在项目中不应该存在。当存在同时具备上述多种特性时,建议采用多个case来针对每一种特性逐一验证,或者采用一个case,逐一执行目标函数并验证其影响。
三、单元测试的种类
本地测试:只能在本地计算机上运行的单元测试,这些测试在Java虚拟机(JVM)上编译运行,减少运行时间。用这种方式来运行对Android 框架没有依赖性或者有依赖但可以通过模拟对象来填充的单元测试。
仪器测试:即在Android设备或模拟器上运行的单元测试。这些测试能够获取设备的信息,使用这种方式来运行那些不能使用模拟对象容易的填充的单元测试。
四、单元测试常用类库
Junit:android单元测试框架
Robolectric:其通过一系列对底层Android元素的替换来实现对原有元素调用的模拟,从而实现脱离模拟器的测 试,在测试服务器请求时,Robolectric的数据模拟和延时发送模拟,给多线程状态下的测试提供了很好的解决方法。
Mockito:该框架可以模拟出对象来,而且本身提供了一些验证函数执行的功能。Mock构造的是一个虚拟的对象,用于解耦真实对象所需要的依赖。Mock得到的对象仅仅是具备测试对象的类型,并不是真实的对象,也就是并没有执行过真实对象的逻辑。
五、实例代码
- 下面这个列子是点击按钮后想气象局发送一个网络请求,成功后跳转显示结果;及其所对应的单元测试
- 查询天气的类QueryWeatherActivity.java
public class QueryWeatherActivity extends Activity { private String weather; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.weather); findViewById(R.id.button_weather).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { loadWeather("shanghai"); } }); } /** * 加载数据 * * @param city */ private void loadWeather(String city) { String url = String.format("http://api.openweathermap.org/data/2.5/weather?q={0}&APPID=7bbbb47522848e8b9c26ba35c226c734&units=metric", city); RequestQueue queue = Volley.newRequestQueue(this); queue.add(new JsonObjectRequest(url, null, new Response.Listener<JSONObject>() { @Override public void onResponse(JSONObject jsonObject) { weather = jsonObject.toString(); NextToActivity(weather); } }, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError volleyError) { Toast.makeText(QueryWeatherActivity.this, volleyError.toString(), Toast.LENGTH_LONG).show(); } })); } public void NextToActivity(String weather) { if (weather != null) { Intent intent = new Intent(QueryWeatherActivity.this, MainActivity.class); intent.putExtra("weather", weather); startActivity(intent); } else { Toast.makeText(QueryWeatherActivity.this, "weather is null", Toast.LENGTH_LONG).show(); } }}
- 针对QueryWeatherActivity做单元测试:主要对是否跳转成功和加载数据是否成功进行 assert。
- 这里会用到两个测试框架Robolectric和Mockito
dependencies { ...... testCompile 'org.robolectric:robolectric:3.0' testCompile "org.mockito:mockito-core:1.10.19"}
-
下面出现的MockHttpStack 是mock出来的一个HttpStack来模拟Volley发送请求的
public class QueryWeatherTest { private QueryWeatherActivity queryWeatherActivity; private String mockWeather; private String weather; @Before public void setUp() throws Exception { queryWeatherActivity = Robolectric.setupActivity(QueryWeatherActivity.class); mockWeather = "由于mock的数据很长就不贴了,具体的源码里都有"; } /** * 跳转页面成功 * weather有数据时才成功跳转 */ @Test public void testNextActivitySucceed(){ weather = "有数据"; queryWeatherActivity.NextToActivity(weather); ShadowActivity shadowActivity = Shadows.shadowOf(queryWeatherActivity); Intent actualIntent = shadowActivity.getNextStartedActivity(); ShadowIntent shadowIntent = Shadows.shadowOf(actualIntent); assertThat((Class < MainActivity>) shadowIntent.getIntentClass(), equalTo(MainActivity.class)); } /** * 跳转页面失败 */ @Test public void testNextActivityFail(){ queryWeatherActivity.NextToActivity(weather); ShadowActivity shadowActivity = Shadows.shadowOf(queryWeatherActivity); Intent actualIntent = shadowActivity.getNextStartedActivity(); assertThat("weather is null", actualIntent, equalTo(null)); } /** * 加载数据成功 * MockHttpStack 是mock一个HttpStack来模拟Volley发送请求的 */ @Test public void testLoadWeatherSucceed() throws IOException, AuthFailureError { MockHttpStack mockHttpStack = new MockHttpStack(mockWeather, 200); String vehicleModel = mockHttpStack.transferString(); assertThat(mockWeather, equalTo(vehicleModel)); } /** * 加载数据失败 401 */ @Test public void testLoadWeatherFail401() throws IOException, AuthFailureError { MockHttpStack mockHttpStack = new MockHttpStack(mockWeather, 401); int statusCode = mockHttpStack.response.getStatusLine().getStatusCode(); assertThat("找不到服务器",401, equalTo(statusCode)); } /** * 加载数据失败 500 */ @Test public void testLoadWeatherFail500() throws IOException, AuthFailureError { MockHttpStack mockHttpStack = new MockHttpStack(mockWeather, 500); int statusCode = mockHttpStack.response.getStatusLine().getStatusCode(); assertThat("没用内容",500, equalTo(statusCode)); } /** * 加载数据失败 * 还有很多失败的情况就不一一列出,这里直接非200都为失败 */ @Test public void testLoadWeatherFail() throws IOException, AuthFailureError { MockHttpStack mockHttpStack = new MockHttpStack(mockWeather, 500); int statusCode = mockHttpStack.response.getStatusLine().getStatusCode(); assertThat("加载失败",200, not(statusCode)); }}
谢谢大家的支持,欢迎大家一起讨论!
源码下载处:http://download.csdn.net/detail/lx_yoyo/9491046
- Android UnitTest
- Android-UnitTest
- Android测试-unitTest
- unittest
- UnitTest
- Android 使用Mockito测试业务逻辑<unittest 之一>
- unittest模块
- MapReduce UnitTest
- seleniumIDE + unittest
- python unittest
- unittest模块
- Python unittest
- unittest+HTMLTestRunner
- unittest理解
- unittest单元测试
- python unittest
- 单元测试UnitTest
- UnitTest 笔记
- cmd的sql执行计划各项属性说明
- MongoDB使用索引
- C语言段错误调试
- Android动画效果translate、scale、alpha、rotate详解
- 关于android手机开发中支持不同分辨率的总结
- Android-UnitTest
- 原始套接字SOCK_RAW
- 过滤器,监听器,拦截器的区别
- 【Android Demo】通过WebService获取今日天气情况
- java 开发环境配置
- hibernate加载对象(get和load的区别)
- Web前端开发-资料分享-JS篇
- Eclipse创建Tomcat时Next按钮是灰色,解决方案!
- 设置Android app的字体不随系统全局字体大小的变动而变动