ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Android单元测试学习总结,androidflash插件

2021-12-28 13:03:26  阅读:186  来源: 互联网

标签:插件 thenReturn when void 单元测试 class androidflash public 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();

}

doXXXthenXXX使用上差不多,一个是调用方法之前设置好返回值,一个是在调用方法之后设置返回值。默认情况下,Mock出的对象的所有非void函数都有返回值,对象类型的默认返回的是null,例如返回int、boolean、String的函数,默认返回值分别是0、falsenull

使用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() {

@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 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 firstMock = mock(List.class);

List 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 list = new ArrayList<>();

List 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生成监控对象:

@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 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 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;

@Spy

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”);

参考:Mockito 中文文档

三、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)

《Android学习笔记总结+最新移动架构视频+大厂安卓面试真题+项目实战源码讲义》

【docs.qq.com/doc/DSkNLaERkbnFoS0ZF】 完整内容开源分享

{

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();

标签:插件,thenReturn,when,void,单元测试,class,androidflash,public,mock
来源: https://blog.csdn.net/m0_65145685/article/details/122190794

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有