在Android Studio中新建一个项目的时候,
app
的
gradle
中会默认添加单元测试的相关依赖库:
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
其中testImplementation
添加的依赖就是本地化测试库, androidTestImplementation
添加的依赖则是Android环境下的测试库,同时,在项目的工程目录下也会默认创建好测试的目录:

其中app/src/test/
下面存放的是Junit本地测试代码,app/src/androidTest/
下面存放的是Android测试代码。
一、本地单元测试
进行本地单元测试需要先了解一些基本的Junit注解:
注解名称 含义 @Test 定义所在方法为单元测试方法,方法必须是public void
@Before 定义所在方法在每个测试用例执行之前执行一次, 用于准备测试环境(如: 初始化类,读输入流等),在一个测试类中,每个@Test方法的执行都会触发一次调用 @After 定义所在方法在每个测试用例执行之后执行一次,用于清理测试环境数据,在一个测试类中,每个@Test方法的执行都会触发一次调用。 @BeforeClass 定义所在方法在测试类里的所有用例运行之前运行一次,方法必须是public static void
,用于做一些耗时的初始化工作(如: 连接数据库) @AfterClass 定义所在方法在测试类里的所有用例运行之后运行一次,方法必须是public static void
,用于清理数据(如: 断开数据连接) @Test (expected = Exception.class) 如果该测试方法没有抛出Annotation中的Exception类型(子类也可以),则测试失败 @Test(timeout=100) 如果该测试方法耗时超过100毫秒,则测试失败,用于性能测试 @Ignore 或者 @Ignore(“太耗时”) 忽略当前测试方法,一般用于测试方法还没有准备好,或者太耗时之类的 @FixMethodOrder 定义所在的测试类中的所有测试方法都按照固定的顺序执行,可以指定3个值,分别是DEFAULT、JVM、NAME_ASCENDING(字母顺序) @RunWith 指定测试类的测试运行器
更多可以参考Junit官网:https://junit.org/junit4/
1. 创建测试类
接下来就可以创建测试类,除了可以手动创建测试类外,可以利用AS快捷键:将光标选中要创建测试类的类名上->按下ALT + ENTER->在弹出的弹窗中选择Create Test
这会弹出下面的弹窗,或者鼠标在类名上右键选择菜单Go to–>Test,也会弹出下面的弹窗

勾选需要进行测试的方法,会自动生成一个测试类:

如果勾选了@Before
或@After
的话也会自动给你生成对应的测试方法
接下来编写测试方法,首先在要测试的目标类中写几个业务方法:
public class SimpleClass {
public boolean isTeenager(int age) {
if (age < 15) {
return true;
return false;
public int add(int a, int b) {
return a + b;
public String getNameById(int id) {
if (id == 1) {
return "小明";
} else if (id == 2){
return "小红";
return "";
然后,测试类:
@RunWith(JUnit4.class)
public class SimpleClassTest {
private SimpleClass simpleClass;
@Before
public void setUp() throws Exception {
simpleClass = new SimpleClass();
@After
public void tearDown() throws Exception {
@Test
public void isTeenager() {
Assert.assertFalse(simpleClass.isTeenager(20));
Assert.assertTrue(simpleClass.isTeenager(14));
@Test
public void add() {
Assert.assertEquals(simpleClass.add(3, 2), 5);
Assert.assertNotEquals(simpleClass.add(3, 2), 4);
@Test
public void getNameById() {
Assert.assertEquals(simpleClass.getNameById(1), "小明");
Assert.assertEquals(simpleClass.getNameById(2), "小红");
Assert.assertEquals(simpleClass.getNameById(10), "");
其中setUp()
是自动生成的添加了@Before
注解,这会在每个测试方法执行前执行,因此在这里创建一个目标对象,也可以选择添加@BeforeClass
注解但这时setUp()
应该改为静态的方法。然后在每个测试方法中编写测试用例,这里使用org.junit.Assert
包中的断言方法,有很多assertXXX
方法,可以自己选择用来判断目标方法的结果是否满足预期。
2. Assert类中的常用断言方法
方法 含义 assertNull(Object object) 断言对象为空 assertNull(String message, Object object) 断言对象为空,如果不为空抛出异常携带指定的message信息 assertNotNull(Object object) 断言对象不为空 assertNotNull(Object object) 断言对象不为空,如果为空抛出异常携带指定的message信息 assertSame(Object expected, Object actual) 断言两个对象引用的是同一个对象 assertSame(String message, Object expected, Object actual) 断言两个对象引用的是同一个对象,否则抛出异常携带指定的message信息 assertNotSame(Object expected, Object actual) 断言两个对象引用的不是同一个对象 assertNotSame(String message, Object expected, Object actual) 断言两个对象引用的不是同一个对象,否则抛出异常携带指定的message信息 assertTrue(boolean condition) 断言结果为true assertTrue(String message, boolean condition) 断言结果为true, 为false时抛出异常携带指定的message信息 assertFalse(boolean condition) 断言结果为false assertFalse(String message, boolean condition) 断言结果为false, 为true时抛出异常携带指定的message信息 assertEquals(long expected, long actual) 断言两个long 类型 expected 和 actual 的值相等 assertEquals(String message, long expected, long actual) 断言两个long 类型 expected 和 actual 的值相等,如不相等则抛异常携带指定message信息 assertEquals(Object expected, Object actual) 断言两个对象相等 assertEquals(String message, Object expected, Object actual) 断言两个对象相等,如果不相等则抛出异常携带指定的message信息 assertEquals(float expected, float actual, float delta) 断言两个 float 类型 expect 和 actual 在 delta 偏差值下相等,delta是误差精度 assertEquals(String message, float expected, float actual, float delta) 断言两个 float 类型 expect 和 actual 在 delta 偏差值下相等,如果不相等则抛出异常携带指定的message信息 assertEquals(double expected, double actual, double delta) 断言两个 double 类型 expect 和 actual 在 delta 偏差值下相等 assertEquals(String message, double expected,double actual, double delta) 断言两个 double 类型 expect 和 actual 在 delta 偏差值下相等,如果不相等则抛出异常携带指定的message信息 assertArrayEquals(T[] expected, T[] actual) 断言两个相同类型的数组的元素一一对应相等 assertArrayEquals(String message, T[] expected, T[] actual) 断言两个相同类型的数组的元素一一对应相等,如果不相等则抛出异常携带指定的message信息 fail() 直接让测试失败 fail(String message) 直接让测试失败并给出message错误信息 assertThat(T actual, Matcher<? super T> matcher) 断言actual和matcher规则匹配 assertThat(String reason, T actual, Matcher<? super T> matcher) 断言actual和matcher规则匹配,否则抛出异常携带指定的reason信息
其中assertEquals
的方法,都对应有一个assertNotEquals
方法,这里不列了,assertThat
是一个强大的方法:
Assert.assertThat(1, is(1));
Assert.assertThat(0, is(not(1)));
Assert.assertThat("hello", startsWith("h"));
List<String> items = new ArrayList<>();
items.add("aaa");
items.add("bbb");
Assert.assertThat(items, hasItem("aaa"));
需要静态导入org.hamcrest.Matchers
类里面的方法,更多匹配方法请参考这个类。
3. 运行测试类
选中测试类右键Run运行,控制面板中就会显示测试结果:

如果所有的测试用例都正常返回了预期的结果,则面板中左侧每个测试方法前面会带一个绿色的对勾,否则方法前面会变成红色感叹号并且控制面板会输出异常,现在来改一个业务方法试一下:
public boolean isTeenager(int age) {
if (age < 15) {
return false;
return false;
这里将age < 15
改为输出false,假设这是我们在编码的时候由于疏忽粗心造成的,然后运行测试类:

控制面板会告诉那一行出错了:

也就是说这里没有返回预期的结果,说明我们编写的业务逻辑是有错误的,这时就需要改bug了。
4. 运行单个测试方法或多个测试类
上面是运行的整个测试类,如果要运行测试类的单个方法,则鼠标只选中某个要运行的测试方法,然后右键选择Run即可。如果要同时运行多个测试类,而如果多个测试类在同一个包下面,则选中多个测试类所在的包目录,然后右键选择Run运行。否则可以通过下面的方式指定,创建一个空的测试类,然后添加注解:
@RunWith(Suite.class)
@Suite.SuiteClasses({SimpleClassTest.class, SimpleClass2Test.class})
public class RunMultiTest {
运行这个测试类就可以将指定的测试类的方法一起运行。
二、Mockito测试框架的使用
前面介绍的只能测试不涉及Android相关Api的java代码用例,如果涉及到Android相关Api的时候,就不方便了,这时如果不依赖第三方库的话可能需要使用仪器化测试跑到Android设备上去运行,于是有一些比较好的第三方的替代框架可以来模拟使用Android的代码测试,Mockito就是基于依赖注入实现的一个测试框架。
1. Mock概念的理解
什么是Mock, 这个单词的中文意思就是“模仿”或者“虚假”的意思,也就是要模仿一个对象,为啥要模仿?
在传统的JUnit单元测试中,没有消除在测试中对对象的依赖,如A对象依赖B对象方法,在测试A对象的时候,我们需要构造出B对象,这样子增加了测试的难度,或者使得我们对某些类的测试无法实现。这与单元测试的思路相违背。
还有一个主要的问题就是本地单元测试由于是运行本地JVM环境,无法依赖Android的api,只靠纯Junit的测试环境很难模拟出完整的Android环境,导致无法测试Android相关的代码,而Mock就能解决这个问题,通过Mock能够很轻易的实现对象的模拟。
添加依赖:
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
testImplementation 'org.mockito:mockito-core:2.19.0'
....
2. Mockito中几种Mock对象的方式
使用之前通过静态方式导入会使用更方便:
// 静态导入会使代码更简洁
import static org.mockito.Mockito.*;
直接mock一个对象:
@Test
public void testMock() {
SimpleClass mockSimple = Mockito.mock(SimpleClass.class);
assertNotNull(mockSimple);
注解方式mock一个对象:
@Mock
SimpleClass simple;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
@Test
public void testMock() {
assertNotNull(simple);
运行器方式mock一个对象:
@RunWith(MockitoJUnitRunner.class)
public class ExampleUnitTest {
@Mock
SimpleClass simple;
@Test
public void testMock() {
assertNotNull(simple);
MockitoRule方式mock一个对象:
public class ExampleUnitTest {
@Mock
SimpleClass simple;
@Rule //<--使用@Rule
public MockitoRule mockitoRule = MockitoJUnit.rule();
@Test
public void testMock() {
assertNotNull(simple);
3. 验证行为
verify(T mock)函数的使用
verify(T mock)
的作用是验证发生的某些行为等同于verify(mock, times(1))
例如:
@Test
public void testMock() {
//创建mock对象
List mockedList = mock(List.class);
//使用mock对象
mockedList.add("one");
mockedList.clear();
//验证mockedList.add("one")是否被调用,如果被调用则当前测试方法通过,否则失败
verify(mockedList).add("one");
//验证 mockedList.clear()是否被调用,如果被调用则当前测试方法通过,否则失败
verify(
mockedList).clear();
@Test
public void testMock() {
mock.someMethod("some arg");
//验证mock.someMethod("some arg")是否被调用,如果被调用则测试方法通过,否则失败
verify(mock).someMethod("some arg");
也就是说如果把调用的方法注释掉,则运行testMock()方法就会失败。
通过verify
关键字,一旦mock对象被创建了,mock对象会记住所有的交互。然后你就可能选择性的验证你感兴趣的交互。
通常需要配合一些测试方法来验证某些行为,这些方法称为"打桩方法"(Stub),打桩的意思是针对mock出来的对象进行一些模拟操作,如设置模拟的返回值或抛出异常等。
常见的打桩方法:
方法名 方法含义 doReturn(Object toBeReturned) 提前设置要返回的值 doThrow(Throwable… toBeThrown) 提前设置要抛出的异常 doAnswer(Answer answer) 提前对结果进行拦截 doCallRealMethod() 调用某一个方法的真实实现 doNothing() 设置void函数什么也不做 thenReturn(T value) 设置要返回的值 thenThrow(Throwable… throwables) 设置要抛出的异常 thenAnswer(Answer<?> answer) 对结果进行拦截
@Test
public void testMock() {
// 你可以mock具体的类型,不仅只是接口
List mockedList = mock(List.class);
// 打测试桩
when(mockedList.get(0)).thenReturn("first");
doReturn("aaaa").when(mockedList).get(1);
when(mockedList.get(1)).thenThrow(new RuntimeException());
doThrow(new RuntimeException()).when(mockedList).clear();
// 输出“first”
System.out.println(mockedList.get(0));
// 因为get(999) 没有打桩,因此输出null, 注意模拟环境下这个地方是不会报IndexOutOfBoundsException异常的
System.out.println(mockedList.get(999));
// get(1)时会抛出异常
System.out.println(mockedList.get(1));
// clear会抛出异常
mockedList.clear();
doXXX
和thenXXX
使用上差不多,一个是调用方法之前设置好返回值,一个是在调用方法之后设置返回值。默认情况下,Mock出的对象的所有非void函数都有返回值,对象类型的默认返回的是null,例如返回int、boolean、String
的函数,默认返回值分别是0、false
和null
。
使用when(T methodCall)
函数
打桩方法需要配合when(T methodCall)
函数,意思是使测试桩方法生效。当你想让这个mock能调用特定的方法返回特定的值,那么你就可以使用它。
when(mock.someMethod()).thenReturn(10);
//你可以使用灵活的参数匹配,例如
when(mock.someMethod(anyString())).thenReturn(10);
//设置抛出的异常
when(mock.someMethod("some arg")).thenThrow(new RuntimeException());
//你可以对不同作用的连续回调的方法打测试桩:
//最后面的测试桩(例如:返回一个对象:"foo")决定了接下来的回调方法以及它的行为。
when(mock.someMethod("some arg"))
.thenReturn("foo")//第一次调用someMethod("some arg")会返回"foo"
.thenThrow(new RuntimeException());//第二次调用someMethod("some arg")会抛异常
//可以用以下方式替代比较小版本的连贯测试桩:
when(mock.someMethod("some arg"))
.thenReturn("one", "two");
//和下面的方式效果是一样的
when(mock.someMethod("some arg"))
.thenReturn("one")
.thenReturn("two");
//比较小版本的连贯测试桩并且抛出异常:
when(mock.someMethod("some arg"))
.thenThrow(new RuntimeException(), new NullPointerException();
使用thenAnswer
为回调做测试桩
when(mock.someMethod(anyString())).thenAnswer(new Answer() {
Object answer(InvocationOnMock invocation) {
Object[] args = invocation.getArguments();
Object mock = invocation.getMock();
return "called with arguments: " + args;
});
// 输出 : "called with arguments: foo"
System.out.println(mock.someMethod("foo"));
使用doCallRealMethod()
函数来调用某个方法的真实实现方法
注意,在Mock环境下,所有的对象都是模拟出来的,而方法的结果也是需要模拟出来的,如果你没有为mock出的对象设置模拟结果,则会返回默认值,例如:
public class Person {
public String getName() {
return "小明";
@Test
public void testPerson() {
Person mock = mock(Person.class);
//输出null,除非设置发回模拟值when(mock.getName()).thenReturn("xxx");
System.out.println(mock.getName());
因为getName()方法没有设置模拟返回值,而getName()返回值是String类型的,因此直接调用的话会返回String的默认值null,所以上面代码如果要想输出getName()方法的真实返回值的话,需要设置doCallRealMethod():
@Test
public void testPerson() {
Person mock = mock(Person.class);
doCallRealMethod().when(mock).getName();
//输出“小明”
System.out.println(mock.getName());
使用doNothing()
函数是为了设置void函数什么也不做
需要注意的是默认情况下返回值为void的函数在mocks中是什么也不做的但是,也会有一些特殊情况。如:
测试桩连续调用一个void函数时:
doNothing().doThrow(new RuntimeException()).when(mock).someVoidMethod();
//does nothing the first time:
mock.someVoidMethod();
//throws RuntimeException the next time:
mock.someVoidMethod();
监控真实的对象并且你想让void函数什么也不做:
List list = new LinkedList();
List spy = spy(list);
//let's make clear() do nothing
doNothing().when(spy).clear();
spy.add("one");
//clear() does nothing, so the list still contains "one"
spy.clear();
使用doAnswer()
函数测试void函数的回调
当你想要测试一个无返回值的函数时,可以使用一个含有泛型类Answer参数的doAnswer()函数做回调测试。假设你有一个void方法有多个回调参数,当你想指定执行某个回调时,使用thenAnswer很难实现了,如果使用doAnswer()将非常简单,示例代码如下:
MyCallback callback = mock(MyCallback.class);
Mockito.doAnswer(new Answer() {
@Override
public Object answer(InvocationOnMock invocationOnMock) throws Throwable {
//获取第一个参数
MyCallback call = invocation.getArgument(0);
//指定回调执行操作
call.onSuccess();
return null;
}).when(mockedObject.requset(callback));
doAnswer(new Answer() {
@Override
public Object answer(InvocationOnMock invocation) throws Throwable {
System.out.println("onSuccess answer");
return null;
}).when(callback).onSuccess();
mockedObject.requset(callback)
需要使用doReturn函数代替thenReturn的情况
如当监控真实的对象并且调用真实的函数带来的影响时
List list = new LinkedList();
List spy = spy(list);
//不可能完成的:真实方法被调用的时候list仍是空的,所以spy.get(0)会抛出IndexOutOfBoundsException()异常
when(spy.get(0)).thenReturn("foo");
//这时你应该使用doReturn()函数
doReturn("foo").when(spy).get(0);
使用doThrow()
函数来测试void函数抛出异常
SimpleClass mock = mock(SimpleClass.class);
doThrow(new RuntimeException()).when(mock).someVoidMethod();
mock.someVoidMethod();
总之使用doThrow(), doAnswer(), doNothing(), doReturn() and doCallRealMethod()
这些函数时可以在适当的情况下调用when()
来解决一些问题., 如当你需要下面这些功能时这是必须的:
- 测试void函数
- 在受监控的对象上测试函数
- 不只一次的测试同一个函数,在测试过程中改变mock对象的行为
4. 验证方法的调用次数
需要配合使用一些方法
方法 含义 times(int wantedNumberOfInvocations) 验证调用方法的次数 never() 验证交互没有发生,相当于times(0) only() 验证方法只被调用一次,相当于times(1) atLeast(int minNumberOfInvocations) 至少进行n次验证 atMost(int maxNumberOfInvocations) 至多进行n次验证 after(long millis) 在给定的时间后进行验证 timeout(long millis) 验证方法执行是否超时 description(String description) 验证失败时输出的内容 verifyZeroInteractions 验证mock对象没有交互
mock.someMethod("some arg");
mock.someMethod("some arg");
//验证mock.someMethod("some arg")被连续调用两次,即如果没有调用两次则验证失败
verify(mock, times(2)).someMethod("some arg");
//注意,下面三种是等价的,都是验证someMethod()被只调用一次
verify(mock).someMethod("some arg");
verify(mock, times(1)).someMethod("some arg");
verify(mock, only()).someMethod("some arg");
mPerson.getAge();
mPerson.getAge();
//验证至少调用2次
verify(mPerson, atLeast(2)).getAge();
//验证至多调用2次
verify(mPerson, atMost
(2)).getAge();
//下面两种等价,验证调用次数为0
verify(mPerson, never()).getAge();
verify(mPerson, times(0)).getAge();
mPerson.getAge();
mPerson.getAge();
long current = System.currentTimeMillis();
System.out.println(current );
//延时1s后验证mPerson.getAge()是否被执行了2次
verify(mPerson, after(1000).times(2)).getAge();
System.out.println(System.currentTimeMillis() - current);
mPerson.getAge();
mPerson.getAge();
//验证方法在100ms超时前被调用2次
verify(mPerson, timeout(100).times(2)).getAge();
@Test
public void testVerifyZeroInteractions() {
Person person = mock(Person.class);
person.eat("a");
//由于person对象发生了交互,所以这里验证失败,把上面的调用注释掉这里就会验证成功
verifyZeroInteractions(person);
//可以验证多个对象没有交互
//verifyZeroInteractions(person,person2 );
@Test
public void testVerifyZeroInteractions() {
Person person = mock(Person.class);
person.eat("a");
verify(person).eat("a");
//注意,这将会无法到达验证目的,不能跟verify()混用
verifyZeroInteractions(person,person2 );
5. 参数匹配器 (matchers)
Mockito以自然的java风格来验证参数值: 使用equals()函数。有时,当需要额外的灵活性时你可能需要使用参数匹配器,也就是argument matchers :
// 使用内置的anyInt()参数匹配器
when(mockedList.get(anyInt())).thenReturn("element");
// 使用自定义的参数匹配器( 在isValid()函数中返回你自己的匹配器实现 )
when(mockedList.contains(argThat(isValid()))).thenReturn("element");
// 输出element
System.out.println(mockedList.get(999));
// 你也可以验证参数匹配器
verify(mockedList).get(anyInt());
常用的参数匹配器:
方法名 含义 anyObject() 匹配任何对象 any(Class type) 与anyObject()一样 any() 与anyObject()一样 anyBoolean() 匹配任何boolean和非空Boolean anyByte() 匹配任何byte和非空Byte anyCollection() 匹配任何非空Collection anyDouble() 匹配任何double和非空Double anyFloat() 匹配任何float和非空Float anyInt() 匹配任何int和非空Integer anyList() 匹配任何非空List anyLong() 匹配任何long和非空Long anyMap() 匹配任何非空Map anyString() 匹配任何非空String contains(String substring) 参数包含给定的substring字符串 argThat(ArgumentMatcher matcher) 创建自定义的参数匹配模式 eq(T value) 匹配参数等于某个值
一些示例代码:
@Test
public void testPersonAny(){
when(mPerson.eat(any(String.class))).thenReturn("米饭");
when(mPerson.eat(anyString())).thenReturn("米饭");
//输出米饭
System.out.println(mPerson.eat("面条"));
@Test
public void testPersonContains(){
when(mPerson.eat(contains("面"))).thenReturn("面条");
//输出面条
System.out.println(mPerson.eat("面"));
@Test
public void testPersonArgThat(){
//自定义输入字符长度为偶数时,输出面条。
when(mPerson.eat(argThat(new ArgumentMatcher<String>() {
@Override
public boolean matches(String argument) {
return argument.length() % 2 == 0;
}))).thenReturn("面条");
//输出面条
System.out.println(mPerson.eat("1234"));
需要注意的是,如果你打算使用参数匹配器,那么所有参数都必须由匹配器提供。例如:
verify(mock).someMethod(anyInt(), anyString(), eq("third argument"));
// 上述代码是正确的,因为eq()也是一个参数匹配器
verify(mock).someMethod(anyInt(), anyString(), "third argument");
// 上述代码是错误的, 因为所有参数必须由匹配器提供,而参数"third argument"并非由参数匹配器提供,因此会抛出异常
像anyObject(), eq()这样的匹配器函数不会返回匹配器。它们会在内部将匹配器记录到一个栈当中,并且返回一个假的值,通常为null。
6. 使用InOrder验证执行执行顺序
验证执行执行顺序主要使用InOrder
函数
如,验证mock一个对象的函数执行顺序:
@Test
public void testInorder() {
List<String> singleMock = mock(List.class);
singleMock.add("小明");
singleMock.add("小红");
// 为该mock对象创建一个inOrder对象
InOrder inOrder = inOrder(singleMock);
// 验证add函数首先执行的是add("小明"),然后才是add("小红"),否则测试失败
inOrder.verify(singleMock).add("小明");
inOrder.verify(singleMock).add("小红");
验证多个mock对象的函数执行顺序:
@Test
public void testInorderMulti() {
List<String> firstMock = mock(List.class);
List<String> secondMock = mock(List.class);
firstMock.add("小明");
secondMock.add("小红");
// 为这两个Mock对象创建inOrder对象
InOrder inOrder = inOrder(firstMock, secondMock);
// 验证它们的执行顺序
inOrder.verify(firstMock).add("小明");
inOrder.verify(secondMock).add("小红");
验证执行顺序是非常灵活的,你不需要一个一个的验证所有交互,只需要验证你感兴趣的对象即可。 你可以选择单个mock对象和多个mock对象混合着来,也可以仅通过那些需要验证顺序的mock对象来创建InOrder对象。
7. 使用Spy监控真实对象
监控真实对象使用spy()
函数生成,或者也可以像@Mock那样使用@Spy
注解来生成一个监控对象, 当你你为真实对象创建一个监控(spy)对象后,在你使用这个spy对象时真实的对象也会也调用,除非它的函数被stub了。尽量少使用spy对象,使用时也需要小心形式。
@Test
public void testSpy() {
List<String> list = new ArrayList<>();
List<String> spy = spy(list);
// 你可以选择为某些函数打桩
when(spy.size()).thenReturn(100);
// 调用真实对象的函数
spy.add("one");
spy.add("two");
// 输出第一个元素"one"
System.out.println(spy.get(0));
// 因为size()函数被打桩了,因此这里返回的是100
System.out.println(spy.size());
// 验证交互
verify(spy).add("one");
verify(spy).add("two");
使用@Spy
生成监控对象:
Person mSpyPerson;
@Test
public void testSpyPerson() {
//将会输出Person 类中getName()的真实实现,而不是null
System.out.println(mSpyPerson.getName());
理解监控真实对象非常重要!有时,在监控对象上使用when(Object)
来进行打桩是不可能或者不切实际的。因此,当使用监控对象时请考虑doReturn|Answer|Throw()
函数族来进行打桩。例如:
List list = new LinkedList();
List spy = spy(list);
// 不可能实现 : 因为当调用spy.get(0)时会调用真实对象的get(0)函数,
// 此时会发生IndexOutOfBoundsException异常,因为真实List对象是空的
when(spy.get(0)).thenReturn("foo");
// 你需要使用doReturn()来打桩
doReturn("foo").when(spy).get(0);
8. 使用ArgumentCaptor进行参数捕获
参数捕获主要为了下一步的断言做准备,示例代码:
@Test
public void argumentCaptorTest() {
List<Object> mock = mock(List.class);
mock.add("John");
//构建要捕获的参数类型,这里是String
ArgumentCaptor argument = ArgumentCaptor.forClass(String.class);
//在verify方法的参数中调用argument.capture()方法来捕获输入的参数
verify(mock).add(argument.capture());
//验证“John”参数捕获
assertEquals("John", argument.getValue());
@Test
public void
argumentCaptorTest2() {
List<Object> mock = mock(List.class);
mock.add("Brian");
mock.add("Jim");
ArgumentCaptor argument = ArgumentCaptor.forClass(String.class);
verify(mock, times(2)).add(argument.capture());
//如果又多次参数调用,argument.getValue()捕获到的是最后一次调用的参数
assertEquals("Jim", argument.getValue());
//如果要获取所有的参数值可以调用argument.getAllValues()
assertArrayEquals(new Object[]{"Brian","Jim"}, argument.getAllValues().toArray());
9. 使用@InjectMocks自动注入依赖对象
有时我们要测试的对象内部需要依赖另一个对象,例如:
public class User {
private Address address;
public void setAddress(Address address) {
this.address = address;
public String getAddress() {
return address.getDetail();
public class Address {
public String getDetail() {
return "detail Address";
User类内部需要依赖Address类,当我们测试的时候需要mock出这两个对象,然后将Address对象传入到User当中,这样如果依赖的对象多了的话就相当麻烦,Mockito 提供了可以不用去手动注入对象的方法,首先使用@InjectMocks
注解需要被注入的对象,如User,然后需要被依赖注入的对象使用@Mock
或@Spy
注解,之后Mockito 会自动完成注入过程,例如:
@InjectMocks
User mTestUser;
@Mock
Address mAddress;
@Test
public void argumentInjectMock() {
when(mAddress.getDetail()).thenReturn("浙江杭州");
System.out.println(mTestUser.getAddress());
这样就不用关心为User 设置Address ,只要为User需要依赖的类添加注解就可以了,然后直接将重点放到测试方法的编写上。
或者使用@Spy监控真实对象注入也可以:
@InjectMocks
User mTestUser;
Address mAddress;
@Test
public void argumentInjectMock() {
// when(mAddress.getDetail()).thenReturn("浙江杭州");
System.out.println(mTestUser.getAddress());
连续调用的另一种更简短的版本:
// 第一次调用时返回"one",第二次返回"two",第三次返回"three"
when(mock.someMethod("some arg")).thenReturn("one", "two", "three");
三、PowerMockito框架使用
Mockito框架基本满足需求但是有一些局限性,如对static、final、private等方法不能mock,PowerMockito就可以解决这些问题,PowerMockito是一个扩展了其它如EasyMock等mock框架的、功能更加强大的框架。PowerMock使用一个自定义类加载器和字节码操作来模拟静态方法,构造函数,final类和方法,私有方法,去除静态初始化器等等。
添加依赖:
testImplementation 'org.powermock:powermock-module-junit4:2.0.2'
testImplementation 'org.powermock:powermock-module-junit4-rule:2.0.2'
testImplementation 'org.powermock:powermock-api-mockito2:2.0.2'
testImplementation 'org.powermock:powermock-classloading-xstream:2.0.2'
1. 普通Mock的方式
public class CommonExample {
public boolean callArgumentInstance(File file) {
return file.exists();
public class CommonExamplePowerMockTest {
@Test
public void testCallArgumentInstance() {
File file = PowerMockito.mock(File.class);
CommonExample commonExample = new CommonExample();
PowerMockito.when(file.exists()).thenReturn(true);
Assert.assertTrue(commonExample.callArgumentInstance(file));
普通Mock方式是外部传递Mock参数,基本上和单独使用Mockito是一样的,使用纯Mockito的api也可以完成这个测试。
2. Mock方法内部new出来的对象
public class CommonExample {
public boolean callArgumentInstance(String path) {
File file = new File(path);
return file.exists();
@RunWith(PowerMockRunner.class)
@PrepareForTest(CommonExample.class)
public class CommonExamplePowerMockTest {
@Test
public void callCallArgumentInstance2() throws Exception {
File file = PowerMockito.mock(File.class);
CommonExample commonExample = new CommonExample();
PowerMockito.whenNew(File.class).withArguments("aaa").thenReturn(file);
PowerMockito.when(
file.exists()).thenReturn(true);
Assert.assertTrue(commonExample.callArgumentInstance("aaa"));
跟前面有一点区别的就是,这里要测试的方法内部创建了File对象,这时需要通过PowerMockito.whenNew(File.class).withArguments("aaa").thenReturn(file)
方法模拟创建File的操作,当File类以aaa的参数创建的时候返回已经mock出来的file对象。同时这时需要在测试类上添加注解@RunWith(PowerMockRunner.class)
和@PrepareForTest(CommonExample.class)
,注意是在类上面添加,不是在方法上,一开始在方法上添加时提示找不到测试方法,@PrepareForTest()
括号里面指定的是要测试的目标类。
3. Mock普通对象的final方法
public class CommonExample {
public boolean callFinalMethod(DependencyClass dependency) {
return dependency.isValidate();
public class DependencyClass {
public final boolean isValidate() {
// do something
return false;
@RunWith(PowerMockRunner.class)
@PrepareForTest({CommonExample.class, DependencyClass.class})
public class CommonExamplePowerMockTest {
@Test
public void callFinalMethod() {
DependencyClass dependency = PowerMockito.mock(DependencyClass.class);
CommonExample commonExample = new CommonExample();
PowerMockito.when(dependency.isValidate()).thenReturn(true);
Assert.assertTrue(commonExample.callFinalMethod(dependency));
同样这里mock出来需要依赖的类的对象,然后传递给调用方法,这里同样需要添加@RunWith
和@PrepareForTest
,@PrepareForTest
可以指定多个目标类,但是这里如果你只需要测试final的话,只添加DependencyClass.class一个就可以了。
4. Mock普通类的静态方法
public final class Utils {
public static String getUUId() {
return UUID.randomUUID().toString();
public class CommonExample {
public String printUUID() {
return Utils.getUUId();
@RunWith(PowerMockRunner.class)
@PrepareForTest(Utils.class)
public class StaticUnitTest {
@Before
public void setUp() throws Exception {
PowerMockito.mockStatic(Utils.class);
@Test
public void getUUId() {
PowerMockito.when(Utils.getUUId()).thenReturn("FAKE UUID");
CommonExample commonExample = new CommonExample();
assertThat(commonExample.printUUID(), is("FAKE UUID"));
同样需要指定@RunWith
和@PrepareForTest
,@PrepareForTest
中指定静态方法所在的类,测试静态方法之前需要调用PowerMockito.mockStatic()
方法来mock静态类,然后就通过when().thenReturn()
方法指定静态方法的模拟返回值即可。
5. verify静态方法的调用次数
@Test
public void testVerify() {
PowerMockito.when(Utils.getUUId()).thenReturn("FAKE UUID");
CommonExample commonExample = new CommonExample();
System.out.println(commonExample.printUUID());
PowerMockito.verifyStatic(Utils.class);
Utils.getUUId();
静态方法通过PowerMockito.verifyStatic(Class c)
进行验证,不过这里跟Mocktio有一点区别的是需要在这个方法的后面再调用一次静态方法,否则不行。这里PowerMockito.verifyStatic(Utils.class)
其实等同于PowerMockito.verifyStatic(Utils.class, times(1))
,如果想验证超过一次的,那么:
@Test
public void testVerify() {
PowerMockito.when(Utils.getUUId()).thenReturn("FAKE UUID");
CommonExample commonExample = new CommonExample();
System.out.println(commonExample.printUUID());
System.out.println(commonExample.printUUID());
PowerMockito.verifyStatic(Utils.class, Mockito.times(2));
Utils.getUUId();
这时PowerMockito.verifyStatic()第一个参数指定静态方法类的Class,第二个参数接收一个VerificationMode类型的参数,因此传递Mockito中的任何验证方法次数的函数都可以,Mockito中的验证函数会返回的是一个VerificationMode类型。同样在PowerMockito.verifyStatic
方法后面要调用一次要验证的静态方法,总感觉这里很奇怪。。。
6. 使用真实返回值
如果在测试的过程中又遇到不需要mock出来的静态方法的模拟返回值,而是需要真实的返回值,怎么办呢,其实跟Mockito一样,PowerMockito同样提供thenCallRealMethod
或者doCallRealMethod
方法:
@Test
public void testRealCall() throws Exception {
PowerMockito.when(Utils.getUUId()).thenReturn(
"FAKE UUID");
//...
PowerMockito.when(Utils.getUUId()).thenCallRealMethod();
//与下面等价
//PowerMockito.doCallRealMethod().when(Utils.class, "getUUId");
System.out.println(Utils.getUUId());
或者直接使用spy监控真实对象也可以:
@Test
public void testRealCall() {
PowerMockito.spy(Utils.class);
System.out.println(Utils.getUUId());
7. Mock私有方法
public class CommonExample {
public boolean callPrivateMethod() {
return isExist();
private boolean isExist() {
return false;
@RunWith(PowerMockRunner.class)
@PrepareForTest(CommonExample.class)
public class PrivateUnitTest {
@Test
public void testCallPrivateMethod() throws Exception {
CommonExample commonExample = PowerMockito.mock(CommonExample.class);
PowerMockito.when(commonExample.callPrivateMethod()).thenCallRealMethod();
PowerMockito.when(commonExample, "isExist").thenReturn(true);
Assert.assertTrue(commonExample.callPrivateMethod());
在使用上跟纯Mockito的没有太大区别,只不过Mock私有方法是通过下面的api实现的:
PowerMockito.when(Object instance, String methodName, Object... arguments)
在PowerMockito中when函数与Mockito相比,最大的变化就是多了一些传递String类型的methodName的重载方法,这样在使用上几乎无所不能了。
8. Mock普通类的私有变量
public class CommonExample {
private static final int STATE_NOT_READY = 0;
private static final int STATE_READY = 1;
private int mState = STATE_NOT_READY;
public boolean doSomethingIfStateReady() {
if (mState == STATE_READY) {
// DO some thing
return true;
} else {
return false;
@Test
public void testDoSomethingIfStateReady() throws Exception {
CommonExample sample = new CommonExample();
Whitebox.setInternalState(sample, "mState", 1);
assertThat(sample.doSomethingIfStateReady(), is(true));
通过Whitebox.setInternalState
来改变私有成员变量,这种情况下不需要指定@RunWith
和@PrepareForTest
。
9. 对静态void方法进行Mock
public class CommonExample {
public static void doSomething(String a) {
System.out.println("doSomething"+a);
@RunWith(PowerMockRunner.class)
@PrepareForTest({CommonExample.class})
public class StaticUnitTest {
@Test
public void testStaticVoid() throws Exception {
PowerMockito.mockStatic(CommonExample.class);
PowerMockito.doNothing().when(CommonExample.class, "doSomething", Mockito.any());
CommonExample.doSomething("aaa");
默认情况下通过PowerMockito.mockStatic
的静态类的void的方法是什么也不做的,但是可以显示的执行doNothing, 上面的代码将doNothing那行注释掉也是什么也不做的。那如果想做一些事而不是doNothing呢,跟Mockito一样,采用doAnswer
:
@Test
public void testStaticVoid() throws Exception {
PowerMockito.mockStatic(CommonExample.class);
PowerMockito.doAnswer(new Answer<Object>() {
@Override
public Object answer(InvocationOnMock invocation) throws Throwable {
System.out.println(invocation.getArguments()[0]);
return null;
}).when(CommonExample.class, "doSomething", Mockito.any());
CommonExample.doSomething("aaa");
10. Mock系统的final静态类
public class CommonExample {
public int callSystemStaticMethod(int a, int b) {
return Math.max(a, a+b);
@RunWith(PowerMockRunner.class)
@PrepareForTest(CommonExample.class)
public class StaticUnitTest {
@Test
public void callSystemStaticMethod() {
CommonExample commonExample = new CommonExample();
PowerMockito.mockStatic(Math.class);
PowerMockito.when(Math.max(anyInt(), anyInt())).thenReturn(100);
Assert.assertEquals(100, commonExample.callSystemStaticMethod(10, -5));
@PrepareForTest
中添加调用系统类所在的类,这里需要注意的是如果你使用PowerMockito来mock系统静态final类,则gradle依赖中不能再添加单纯Mockito的依赖库,否则这里将不能mock成功,会提示Mockito can not mock/spy final class
, 因为PowerMockito本身已经有对Mockito的依赖库支持了,所以只依赖PowerMockito就可以了。除了系统静态final类的情况,其他的情况下PowerMockito和Mockito可以同时依赖(我测试是没有问题的)。另外单纯的Mockito新版本中也支持对 final 类 final 方法的 Mock,但是需要添加配置文件并不友好。
四、Robolectric测试框架的使用
由于Robolectric部分的内容比较长,所以单独放了一篇文章中:Android单元测试框架Robolectric的学习使用
五、Espresso测试框架的使用
Espresso是用于Android仪器化测试的测试框架,是谷歌官方主推的一个测试库。由于Espresso部分的内容也比较长,所以单独放了一篇文章中:Espresso测试框架的使用
Android单元测试主要分为以下两种本地单元测试(Junit Test), 本地单元测试是纯java代码的测试,只运行在本地电脑的JVM环境上,不依赖于Android框架的任何api, 因此执行速度快,效率较高,但是无法测试Android相关的代码。Android单元测试(Android Test),是针对Android相关代码的测试,需要运行在真机设备或模拟器上,运行速度较慢,但是可以...
2016年 1 月 5 日 摘要: 本文首先介绍了Android开发环境的安装和部署过程;之后介绍了Android项目的架构及 应用程序组成,着重讲解了手机用户界面的布局方法和常见开发控件的使用;然后介绍 了Android中的文件存储管理、SQLite数据库存取与共享、2D绘图设计、多媒体应用以及 电话和短信开发等知识;最后介绍了Android中的单元测试以及国际化的方法,通过发布 案例程序完成Android知识的讲解,同时运用了photoshop,实现了对界面的优化设计。 关键词:Android;开发;SQL;多媒体运用;PHOTOSHOP 目录 一、实训背景及目的要求 4 1.1背景简介 4 1.2实训目的及要求 4 二、设计思路 5 2.1设计题目 5 2.2功能分析 5 2.3模块划分 5 三、设计实现及代码分析 5 3.1第一个Activity 5 3.1.1布局文件:main.xml: 5 3.1.2源代码文件:MainActivity.java 9 3.2第二个Activity 12 3.2.1布局文件:result.xml 12 3.2.2源代码文件:ResultActivity.java 13 3.3字符串资源文件:strings.xml 17 3.4程序清单文件:AndroidManifest.xml 18 四、程序功能测试及截图 19 4.1工程项目目录 19 4.2程序运行界面: 19 4.3未填身高提示: 20 4.4计算示例: 21 五、课程设计(实训)总结 21 一、实训背景及目的要求 1.1背景简介 Android(读音:['ændrɔid])是一种以Linux为基础的开放源码操作系统,主要使用 于便携设备,目前尚未有统一中文名称,中国大陆地区较多人使用安卓或安致。Androi d操作系统最初由Andy Rubin创办[5],最初只支持手机。2005年由Google收购注资,并拉拢多家制造商组成开 放手机联盟(Open Handset Alliance)开发改良,逐渐扩展到到平板电脑及其他领域上[6]。 2010年末数据显示,仅正式推出两年的操作系统的Android已经超越称霸十年的诺基亚S ymbian系统,跃居全球最受欢迎的智慧手机平台。采用Android系统手机厂商包括HTC、 Samsung、Motorola、Lenovo、LG、Sony Ericsson等。 1.2实训目的及要求 Android以Linux为核心的Android行动平台,使用Java作为编程语言。本实训是在学 习java语言程序设计的基础上进行的一次综合实践。通过综合训练,要求学生掌握java 语言程序设计的基本技能和Android编程的应用,并较系统地掌握JAVA语言程序设计开发 方法以及帮助文件的使用等,使学生通过本次实训,能够进行独立的Android应用程序开 发,能够在实际操作中得到进一步的提高,为以后的学习和工作打下良好的基础。 目的: 1、培养学生运用所学课程Java语言程序设计的理论知识和技能,分析解决计算机实 际应用中的问题的能力。 2、培养学生在Java语言程序设计的基础上,开发Android应用程序的思想和方法。 3、培养学生调查研究、查阅技术文献、资料、手册以及编写技术文献的能力。 通过课程设计,要求学生在指导教师的指导下,独立完成课程设计的全部内容,包括 : 1、确定开发的程序,收集和调查有关技术资料。 2、按软件工程步骤进行程序设计。 3、对完成的程序进行测试和完善。 4、完成课程设计报告。 二、设计思路 2.1设计题目 以Android系统的UI界面开发为基础,设计一个可以简单计算标准体重的应用程序, 要求以2个Acitivity实现,第一个Activity作为输入界面,第二个Activity作为结果输 出界面,具体实现细节自行设计。 2.2功能分析 该设计题目要求实现可计算输出标准体重功能的应用程序。通过查阅资料可知,按照 世界卫生组织推荐的计算标准体重的方法,需要获知的输入信息有性别、身高。故可在 第一屏设置有单选框以确定性别,输入框以获取身高。另,为了增加程序的实用性,可 再设一可选输入框,用来得到实际体重,与标准体重对比,给出用户一些健康提议。第 二屏设置有结果输出显示区域与健康提示显示区域。 2.3模块划分 通过程序功能分析,可将程序划分为2个模块,即2个Activity: 第一个Activity:两个单选框(RadioButton)获取性别,一个输入框(EditText) 获取身高,一个可选输入框(EditText)获取实际体重,一个按钮(Button)及一些提 示文本。 第二个Activity:一个文本显示区(TextViw)显示计算结果,一个可选文本显示区 (TextView
技术体系包括:
J2SE/J2ME/J2EE/JAVA代码优化/Flex(BlazeDS、PureMVC等技术)/LDAP/C++/Portal/即时通讯/数据建模/UML/UML设计工具(Rose、EA、PD等)/移动办公(Android、Symbian、Wap等技术)/项目管理(敏捷开发等)/软件架构(NoSQL、SaaS、设计模式等)/数据库(MySQL、Oracle、EDB、SQLServer等)/测试(单元测试、压力测试)/linux服务器等
其中含有大量实例源代码。
这里需要说明的时,该文档是本人5年工作经验的积累,文档中大部分知识点来源于实际工作中的总结,(除了JAR等资源文件外)其代码都是可运行的,还有一部分知识来源于网络或者其他书籍,这里做一些收集,使该体系更加完善。
2016年 1 月 5 日 摘要: 本文首先介绍了Android开发环境的安装和部署过程;之后介绍了Android项目的架构及 应用程序组成,着重讲解了手机用户界面的布局方法和常见开发控件的使用;然后介绍 了Android中的文件存储管理、SQLite数据库存取与共享、2D绘图设计、多媒体应用以及 和短信开发等知识;最后介绍了Android中的单元测试以及国际化的方法,通过发布案例 程序完成Android知识的讲解,同时运用了photoshop,实现了对界面的优化设计。 关键词:Android;开发;SQL;多媒体运用;PHOTOSHOP 目录 一、实训背景及目的要求 4 1.1背景简介 4 1.2实训目的及要求 4 二、设计思路 5 2.1设计题目 5 2.2功能分析 5 2.3模块划分 5 三、设计实现及代码分析 5 3.1第一个Activity 5 3.1.1布局文件:main.xml: 5 3.1.2源代码文件:MainActivity.java 9 3.2第二个Activity 12 3.2.1布局文件:result.xml 12 3.2.2源代码文件:ResultActivity.java 13 3.3字符串资源文件:strings.xml 17 3.4程序清单文件:AndroidManifest.xml 18 四、程序功能测试及截图 19 4.1工程项目目录 19 4.2程序运行界面: 19 4.3未填身高提示: 20 4.4计算示例: 21 五、课程设计(实训)总结 21 一、实训背景及目的要求 1.1背景简介 Android(读音:['ændrɔid])是一种以Linux为基础的开放源码操作系统,主要使用 于便携设备,目前尚未有统一中文名称,中国大陆地区较多人使用安卓或安致。Androi d操作系统最初由Andy Rubin创办[5],最初只支持手机。2005年由Google收购注资,并拉拢多家制造商组成开 放手机联盟(Open Handset Alliance)开发改良,逐渐扩展到到平板电脑及其他领域上[6]。 2010年末数据显示,仅正式推出两年的操作系统的Android已经超越称霸十年的诺基亚S ymbian系统,跃居全球最受欢迎的智慧手机平台。采用Android系统手机厂商包括HTC、 Samsung、Motorola、Lenovo、LG、Sony Ericsson等。 1.2实训目的及要求 Android以Linux为核心的Android行动平台,使用Java作为编程语言。本实训是在学 习java语言程序设计的基础上进行的一次综合实践。通过综合训练,要求学生掌握java 语言程序设计的基本技能和Android编程的应用,并较系统地掌握JAVA语言程序设计开发 方法以及帮助文件的使用等,使学生通过本次实训,能够进行独立的Android应用程序开 发,能够在实际操作中得到进一步的提高,为以后的学习和工作打下良好的基础。 目的: 1、培养学生运用所学课程Java语言程序设计的理论知识和技能,分析解决计算机实 际应用中的问题的能力。 2、培养学生在Java语言程序设计的基础上,开发Android应用程序的思想和方法。 3、培养学生调查研究、查阅技术文献、资料、手册以及编写技术文献的能力。 通过课程设计,要求学生在指导教师的指导下,独立完成课程设计的全部容,包括: 1、确定开发的程序,收集和调查有关技术资料。 2、按软件工程步骤进行程序设计。 3、对完成的程序进行测试和完善。 4、完成课程设计报告。 二、设计思路 2.1设计题目 以Android系统的UI界面开发为基础,设计一个可以简单计算标准体重的应用程序, 要求以2个Acitivity实现,第一个Activity作为输入界面,第二个Activity作为结果输 出界面,具体实现细节自行设计。 2.2功能分析 该设计题目要现可计算输出标准体重功能的应用程序。通过查阅资料可知,按照世界 卫生组织推荐的计算标准体重的方法,需要获知的输入信息有性别、身高。故可在第一 屏设置有单选框以确定性别,输入框以获取身高。另,为了增加程序的实用性,可再设 一可选输入框,用来得到实际体重,与标准体重对比,给出用户一些健康提议。第二屏 设置有结果输出显示区域与健康提示显示区域。 2.3模块划分 通过程序功能分析,可将程序划分为2个模块,即2个Activity: 第一个Activity:两个单选框(RadioButton)获取性别,一个输入框(EditText) 获取身高,一个可选输入框(EditText)获取实际体重,一个按钮(Button)及一些提 示文本。 第二个Activity:一个文本显示区(TextViw)显示计算结果,一个可选文本显示区 (TextView)显示提示信
在编写代码测试用例时,Mockito是开发人员最常见的选择之一。 然后我们面对的问题是,如何使用Mockito的thenReturn()和thenAnswer()方法? 如果您也面临这个问题,请不要担心每个人都面临或已经遇到了这个问题,我们将在这里解决!! 所以,开始吧...
Mockito是最著名的测试模拟框架之一。 让我们假设您已经了解了模仿。 如果没有,您可以在我们继续之前访问官方...
androidTest是整合测试,可以运行在设备或虚拟设备上,需要编译打包为APK在设备上运行,可以实时查看细节
test 是单元测试,运行在本地开发机上,可以脱离Android运行环境,速度快
Android Studio 测试分 androidTest 安卓测试(下图绿箭头)和 test (java测试/junit测试)(下图红箭头),我们下面的实例是test(单元测试)
在实际开发中,开发android软件的过程需要不断的进行测试。而是用Junit测试框架,则是正规android开发的必用技术,在Junit中可以得到组件,可以模拟发送事件和检测程序处理的正确性。
第一步:首先在AndroidManifest.xml中加入下面红色代码(把单元测试库引进到此项目中):
android:icon="@drawable/ic_launcher"
Android开发中单元测试的两种方式
一位优秀的程序员也同样不能保证自己的程序没有bug,因此编写合适的测试程序是完全有必要的,这样也会降低程序在后期出现各种奇奇怪怪bug的可能,降低维护成本,未雨绸缪将bug扼杀在摇篮之中。
看到网上有很多依旧用写java单元测试的方式在写android程序的单元测试程序——junit,当然我一直都反感将不合时宜的东西强搬到新的技术应用以获取一席之地的这种
IllegalStateException: Cannot call this method while RecyclerView is computing a layout or scrolling
23492
int main(void)
double a,b,c,x1,×2,r,i,delt;
printf("Please input the equation coefficients a,b.c:");
scanf("%f,%f,%If",8.a,8.b,8c);
printf("\nThen equation");
if(fabs(a)<=1e-6)
printf("is not a quadratic\n");
delt=b*b-4*a*c;
if(fabs(delt)<=1e-6)
printf("has two equal roots:%8.4f\n",-b/(2*a));
if(delt>le-6)
x1=(一b+sqrt(delt))/(2*a);
x2=(-b-sqrt(delt))/(2*a);
printf("has distinct real roots:%8.4f and %8.4f\n",x1,x2);
r=—b/(2*a);
i=sqrt(-delt)/(2*a);
printf("has complex roots:\n");
printf("%8.4f+%8.4fi\n",r,i);
printf("%8.4f-%8.4fi\n",r,i);
return 0;
Flutter 笔记 | Flutter 核心原理(三)布局(Layout )过程
CSDN-Ada助手:
恭喜你这篇博客进入【CSDN每天值得看】榜单,全部的排名请看 https://bbs.csdn.net/topics/615624689。
Jetpack Compose中的绘制流程和自定义布局
idiot_leon:
太硬核了!十分震撼!十分感谢!
Flutter 笔记 | Flutter 中的路由、包、资源、异常和调试
CSDN-Ada助手:
恭喜你这篇博客进入【CSDN每天值得看】榜单,全部的排名请看 https://bbs.csdn.net/topics/615447085。
Android 10 申请动态权限以后仍然无法读写文件的解决方案
Patric_K_Star:
android:requestLegacyExternalStorage="true" 查了这一句