首页 > 系统 > Android > 正文

Android 单元测试介绍

2019-11-09 16:14:53
字体:
来源:转载
供稿:网友

1、JUnit 最基础、应用最为广泛的单元测试框架 2、Mockito java中最流行的mock(模拟)测试框架,只能mock出public 3、PowerMock 可以mock静态、final、PRivate方法的框架 4、编写测试用例

JUnit是什么?

JUnit用于编写和运行可重复的自动化测试开源框架,保证代码按预期工作

Junit有哪些作用?

1、断言测试预期结果 2、测试功能共享通用的测试数据。 3、测试套件轻松地组织和运行测试。 4、运行图形、文本测试

测试代码在工程目录的位置

这里写图片描述

Junit注解

@Test 测试注释,附着一个测试用例

@Ignore 注释的测试用例不被执行

@BeforeClass 在类的所有测试之前,只执行一次

@Before 在测试类的每个测试用例之前执行,必要的先决条件

@AfterClass 在类的所有用例之后执行,只执行一次,用于清理。

@After 在每个测试用例之后执行,重置变量,删除临时变量

Junit注解示例

这里写图片描述

断言

确定被测试的方法是否按照预期的效果正常工作。

如下图所示: 这里写图片描述

assertEquals([String message], expected, actual) message 可选,错误发生时报告消息。 expected 是期望值。 actual 是测试方法返回值

Mock测试

在测试过程中,存在不容易构造、获取的对象,使用虚拟的Mock对象,简化测试的测试方法。

Mock功能

1、模拟代码对类或接口的依赖 2、验证调用的依赖行为 3、将单元测试的耦合分解开

Mockito注解

Mock:模拟外部依赖,提供测试所需要的数据 Spy:监视一个方法被调用的情况 Stub:认为设定方法的返回数据 Captor:捕获方法的参数,验证是否符合要求 这里写图片描述

InjectMocks:验证Mock对象方法调用次数,顺序、参数等 这里写图片描述

package com.sfnp.warehouse.modul.cityexpress.knight.receive.first;import com.google.gson.Gson;import com.sfnp.warehouse.base.BaseHttpRequestListener;import com.sfnp.warehouse.bean.GetPickupTaskResp;import com.sfnp.warehouse.data.Repository;import org.junit.Before;import org.junit.Test;import org.junit.runner.RunWith;import org.mockito.ArgumentCaptor;import org.powermock.api.mockito.PowerMockito;import org.powermock.core.classloader.annotations.PrepareForTest;import org.powermock.modules.junit4.PowerMockRunner;import java.util.ArrayList;import java.util.List;import static org.mockito.Matchers.any;import static org.mockito.Matchers.eq;import static org.mockito.Mockito.mock;import static org.mockito.Mockito.spy;import static org.mockito.Mockito.verify;import static org.mockito.Mockito.when;/** * Created by dev on 17/1/13. */@RunWith(PowerMockRunner.class)@PrepareForTest({Repository.class})public class FirstHandlePresenterTest { private FirstHandlePresenter presenter; private FirstHandleContract.View view; private Repository repository; @Before public void before() { presenter = spy(FirstHandlePresenter.class); view = mock(FirstHandleContract.View.class); when(presenter.getView()).thenReturn(view); } @Test public void should_showEmpty_when_queryKnightTask() throws Exception { //given //when presenter.queryKnightTask(""); //then verify(view).showEmptyKnight(); } @Test public void should_queryKnightTaskSuccess_when_queryKnightTask() throws Exception { //given GetPickupTaskResp resp = new GetPickupTaskResp(); List<String> waybillList = new ArrayList<>(); waybillList.add("260951001004"); resp.setWaybillList(waybillList); repository = mock(Repository.class); PowerMockito.mockStatic(Repository.class); when(Repository.getInstance()).thenReturn(repository); //when presenter.queryKnightTask("015555"); //then //then ArgumentCaptor<BaseHttpRequestListener> captor = ArgumentCaptor.forClass(BaseHttpRequestListener.class); verify(repository).getPickupTask(eq("015555"), captor.capture()); captor.getValue().onSuccess(new Gson().toJson(resp)); //then verify(view).queryKnightTaskSuccess(any(GetPickupTaskResp.class)); } @Test public void should_showNotFoundTask_when_queryKnightTask() throws Exception { //given GetPickupTaskResp resp = new GetPickupTaskResp(); repository = mock(Repository.class); PowerMockito.mockStatic(Repository.class); when(Repository.getInstance()).thenReturn(repository); //when presenter.queryKnightTask("015555"); //then //then ArgumentCaptor<BaseHttpRequestListener> captor = ArgumentCaptor.forClass(BaseHttpRequestListener.class); verify(repository).getPickupTask(eq("015555"), captor.capture()); captor.getValue().onSuccess(new Gson().toJson(resp)); //then verify(view).showNotFoundTask(); } @Test public void should_playErrorVoice_when_onResultError() throws Exception { //given //when presenter.onResultError("015555"); //then verify(view).playErrorVoice(); }}

PowerMock注解

@RunnerWith 告诉JUnit用PowerMockRunner执行测试用例

@PrepareForTest 告诉PowerMock准备对final,private, static方法的类进行测试

示例如下: 这里写图片描述

这里写图片描述

依赖库

这里写图片描述

配置maven库 这里写图片描述

在module的build.gradle文件夹的Android下加入如下内容 这里写图片描述

robolectric和shadows的使用

这两个框架主要用于对Android的view层代码测试

package com.sfnp.warehouse.modul.outwarehouse.delivery;import android.content.Intent;import android.view.KeyEvent;import android.widget.Button;import android.widget.TextView;import com.sfnp.warehouse.BuildConfig;import com.sfnp.warehouse.R;import com.sfnp.warehouse.bean.OutWarehouseRes;import com.sfnp.warehouse.bean.SchGroup;import com.sfnp.warehouse.constant.IntentKey;import com.sfnp.warehouse.constant.ResultCode;import com.sfnp.warehouse.util.BaseShadowUtil;import com.sfnp.warehouse.util.ShadowSoundUtils;import com.sfnp.warehouse.widget.ClearEditText;import org.junit.Assert;import org.junit.Before;import org.junit.Test;import org.junit.runner.RunWith;import org.robolectric.Robolectric;import org.robolectric.RobolectricTestRunner;import org.robolectric.annotation.Config;import org.robolectric.annotation.Implementation;import org.robolectric.annotation.Implements;import org.robolectric.shadows.ShadowDialog;import org.robolectric.shadows.ShadowProgressDialog;import org.robolectric.shadows.ShadowToast;import java.util.ArrayList;import java.util.List;import static org.junit.Assert.assertEquals;@RunWith(RobolectricTestRunner.class)@Config(constants = BuildConfig.class, sdk = 22, shadows = {DeliveryActivityTest.ShadowDeliveryPresenter.class, ShadowSoundUtils.class})public class DeliveryActivityTest { private DeliveryActivity activity; @Before public void setUp() throws Exception { ShadowDeliveryPresenter.reset(); ShadowSoundUtils.reset(); Intent intent = new Intent(); SchGroup schGroup = new SchGroup(); schGroup.setFullName("xx"); schGroup.setEmpId("11"); schGroup.setIsGroup(true); intent.putExtra(IntentKey.SCHGROUP, schGroup); activity = Robolectric.buildActivity(DeliveryActivity.class, intent).setup().get(); } @Test public void should_init_when_oncreate() throws Exception { Assert.assertEquals(1, ShadowDeliveryPresenter.getType()); } @Test public void should_addWaybill_when_onReceiveScan() throws Exception { //given //when activity.onReceiveScan("755123456789"); //then Assert.assertEquals(2, ShadowDeliveryPresenter.getType()); } @Test public void should_onKeyDown_when_onKeyDown_code_is_119() throws Exception { //given KeyEvent event = new KeyEvent(KeyEvent.ACTION_DOWN, 119); int code = 119; //when boolean flag = activity.onKeyDown(code, event); //then Assert.assertTrue(flag); } @Test public void should_onKeyDown_when_onKeyDown_code_not_is_119() throws Exception { //given KeyEvent event = new KeyEvent(KeyEvent.ACTION_UP, 55); int code = 55; //when boolean flag = activity.onKeyDown(code, event); //then Assert.assertTrue(!flag); } @Test public void should_onActivityResult_when_onActivityResult_is_ResultCode_FINISH_ACTIVITY() throws Exception { //given int code = ResultCode.FINISH_ACTIVITY; //when activity.onActivityResult(0, code, null); //then Assert.assertTrue(activity.isFinishing()); } @Test public void should_showProgress_when_showProgress() throws Exception { //given //when activity.showProgress(); //then Assert.assertEquals(1, ShadowProgressDialog.getShownDialogs().size()); } @Test public void should_showGroupView_when_showGroupView() throws Exception { //given //when activity.showGroupView(); TextView handOutInfoTV = (TextView) activity.findViewById(R.id.employee_info_tv); //then Assert.assertEquals("xx (11) 小组", handOutInfoTV.getText().toString()); } @Test public void should_showPersonalView_when_showPersonalView() throws Exception { //given String message = "xx (11) 个人"; //when activity.showPersonalView(); TextView handOutInfoTV = (TextView) activity.findViewById(R.id.employee_info_tv); //then Assert.assertEquals(message, handOutInfoTV.getText().toString()); } @Test public void should_showEmptyWaybill_when_showEmptyWaybill() throws Exception { //given String message = "运单号不能为空,请重新输入"; //when activity.showEmptyWaybill(); //then Assert.assertEquals(message, ShadowToast.getTextOfLatestToast()); } @Test public void should_showInvalidWaybill_when_showInvalidWaybill() throws Exception { //given String message = "无效的运单号,请重新输入"; //when activity.showInvalidWaybill(); //then Assert.assertEquals(message, ShadowToast.getTextOfLatestToast()); } @Test public void should_showRepeatWaybill_when_showRepeatWaybill() throws Exception { //given String message = "已添加过该件,请不要重复添加"; //when activity.showRepeatWaybill(); //then Assert.assertEquals(message, ShadowToast.getTextOfLatestToast()); } @Test public void should_startRepeatSound_when_startRepeatSound() throws Exception { //given //when activity.startRepeatSound(); //then assertEquals(R.raw.scan_repeat, ShadowSoundUtils.getType()); } @Test public void should_playProhibitOutWarehouse_when_playProhibitOutWarehouse() throws Exception { //given //when activity.playProhibitOutWarehouse(); //then assertEquals(R.raw.prohibit_out_warehouse, ShadowSoundUtils.getType()); } @Test public void should_playNormal_when_playNormal() throws Exception { //given //when activity.outWarehouseNormal("755123456789"); TextView mTextScanned = (TextView) activity.findViewById(R.id.textScanned); ClearEditText mTextInput = (ClearEditText) activity.findViewById(R.id.textScanResult); //then assertEquals("", mTextInput.getText().toString()); assertEquals("1", mTextScanned.getText().toString()); } @Test public void should_outWarehouseNormal_when_outWarehouseNormal() throws Exception { //given //when activity.playNormal(); //then assertEquals(R.raw.scan_nomal, ShadowSoundUtils.getType()); } @Test public void should_outWarehouseHide_when_outWarehouseHide() throws Exception { //given //when activity.outWarehouseHide(new OutWarehouseRes()); Button btnTakeout = (Button) ShadowDialog.getLatestDialog().findViewById(R.id.btn_cancel); btnTakeout.performClick(); //then Assert.assertTrue(!ShadowDialog.getLatestDialog().isShowing()); } @Test public void should_outWarehouseWantedByDialog_when_outWarehouseWantedByDialog() throws Exception { //given OutWarehouseRes res = new OutWarehouseRes(); res.setWantedList(new ArrayList<String>()); //when activity.outWarehouseWantedByDialog(res); TextView mTextScanned = (TextView) activity.findViewById(R.id.textScanned); ClearEditText mTextInput = (ClearEditText) activity.findViewById(R.id.textScanResult); //then Assert.assertTrue(ShadowDialog.getLatestDialog().isShowing()); assertEquals("", mTextInput.getText().toString()); assertEquals("1", mTextScanned.getText().toString()); } @Test public void should_outWarehouseWantedByText_when_outWarehouseWantedByText() throws Exception { //given OutWarehouseRes res = new OutWarehouseRes(); res.setWantedList(new ArrayList<String>()); //when activity.outWarehouseWantedByText(res); TextView mTextScanned = (TextView) activity.findViewById(R.id.textScanned); ClearEditText mTextInput = (ClearEditText) activity.findViewById(R.id.textScanResult); //then assertEquals("", mTextInput.getText().toString()); assertEquals("1", mTextScanned.getText().toString()); } @Test public void should_outWarehouseSuccess_when_outWarehouseSuccess() throws Exception { //given //when activity.outWarehouseSuccess("755123456789"); TextView mTextScanned = (TextView) activity.findViewById(R.id.textScanned); ClearEditText mTextInput = (ClearEditText) activity.findViewById(R.id.textScanResult); //then assertEquals("", mTextInput.getText().toString()); assertEquals("1", mTextScanned.getText().toString()); } @Test public void should_outWarehouseFail_when_outWarehouseFail() throws Exception { //given String message = "出仓失败"; //when activity.outWarehouseFail(); //then assertEquals(message, ShadowToast.getTextOfLatestToast()); } @Test public void should_onClick_when_onClick() throws Exception { //given Button mBtnAdd = (Button) activity.findViewById(R.id.btnAdd); //when activity.onClick(mBtnAdd); //then Assert.assertEquals(2, ShadowDeliveryPresenter.getType()); } @Implements(DeliveryPresenter.class) public static class ShadowDeliveryPresenter extends BaseShadowUtil { @Implementation public void initSchInfo(boolean isGroup) { setType(1); } @Implementation public void addWaybill(String waybillNo, SchGroup schGroup, List<String> waybillList, int flag) { setType(2); } @Implementation public void outWarehouse(String waybillNo, SchGroup schGroup) { setType(3); } @Implementation public void retentionBinSuccess(boolean isSuccess) { setType(4); } @Implementation public void takeOut(String waybillNo, String targetEmpCode, boolean isGroup) { setType(5); } }}

最后鼠标右击选中运行(带覆盖率和普通两种运行方式) 这里写图片描述


发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表