android单元测试(4)Mockito与接⼝、抽象类、静态⽅法、
kotlin、模板
1.官⽅⽂档
2.模拟接⼝、抽象类、内部抽象类
2.1 模拟接⼝
1interface Interface1 { fun say() = "said" }
2interface Interface2 : Interface1 { override fun say() = "said" }
3
4 @RunWith(AndroidJUnit4::class)
5class interface_test(){
6 @Test @SmallTest //测试 interface
7 fun test_mock_interface(){
8// mock creation
9 val mock = k(Interface1::class.java)
10// when
11 Mockito.`when`(mock.say()).thenReturn("mock said")
12// then
13 assertTrue(mock.say() == "mock said")
14
15// spy
16 val spy = spy(Interface1::class.java)
17 Mockito.`when`(spy.say()).thenReturn("spy said")
18 assertTrue(spy.say() == "spy said")
19 }
20 }
2.2 模拟抽象类
使⽤mock()并指定setting可以⽣成任意抽象类的模拟对象
使⽤spy()⽆法对构造有参数的抽象类⽣成模拟对象。
1abstract class Abstract1 { fun say() = "said" }
2abstract class Abstract2(var name: String) { fun say() = "said" }
3
4 @RunWith(AndroidJUnit4::class)
5class Abstract_test(){
6
7 @Test @SmallTest //测试⽆构造参数的 abstract 类
8 fun test_mock_abstract(){
9// mock creation
10 val mock = k(Abstract1::class.java)
11// when
12 Mockito.`when`(mock.say()).thenReturn("mock said")
13var words = mock.say()
14// then
15 Mockito.verify(mock).say()
16 assertTrue(words == "mock said")
17
18// spy
19 val setting = Mockito.withSettings().useConstructor().defaultAnswer(CALLS_REAL_METHODS)
20 val spy = spy(Abstract1::class.java)
21 Mockito.`when`(spy.say()).thenReturn("spy said")
22 words = spy.say()
23 Mockito.verify(spy).say()
24 assertTrue(words == "spy said")
25 }
26 @Test @SmallTest //测试有构造参数的 abstract 类,这时spy⽆法通过
27 fun test_mock_abstract_args(){
28// spy
29 // val spy = spy(Abstract2::class.java) // error,⽆法spy
30 val setting = Mockito.withSettings().useConstructor("args").defaultAnswer(CALLS_REAL_METHODS)
31 val spy = k(Abstract2::class.java,setting)
32 Mockito.`when`(spy.say()).thenReturn("spy said")
33 val words = spy.say()
34 Mockito.verify(spy).say()
35 assertTrue(words == "spy said")
36 }
37 @Test @SmallTest //测试有构造参数的 inner abstract 类
38 fun test_mock_abstract_inner(){
39abstract class Abstract3(var name: String) { fun say() = "said" }
40// spy
41 val setting = Mockito.withSettings().useConstructor("inner")/*.outerInstance(outerInstance)*/.defaultAnswer(CALLS_REAL_METHODS)
42 val spy = k(Abstract3::class.java,setting)
43 Mockito.`when`(spy.say()).thenReturn("inner said")
44 val words = spy.say()
45 Mockito.verify(spy).say()
46 assertTrue(words == "inner said")
47 }
48 }
3.打桩静态⽅法
3.1 要求
使⽤
java要使⽤ try-with-resources 语法,kotlin可使⽤use()
3.2 ⽰例
java 代码:
1 @RunWith(AndroidJUnit4.class)
2public class MockitoJava {
3public static int value() { return -1;}
4
5 @Test @SmallTest
6public void testMockStatic(){
7 assertTrue(-1 == MockitoJava.value());
8try(MockedStatic mock = kStatic(MockitoJava.class)) {
9 mock.when(MockitoJava::value).thenReturn(100);
10 assertTrue(100 == MockitoJava.value());
11//超出范围后结束
12 }
13 assertTrue(-1 == MockitoJava.value());
14 }
15 }
kotlin 暂时不⽀持
1 @Test @SmallTest
2 fun test_mock_static2(){
3// given
4 kStatic(StuStatic1::class.java).use {
5// when
6 Mockito.`when`(StuStatic1.value1()).thenReturn(200 )
7// then
8 assertTrue(StuStatic1.value1() == 200 )
9
10 it
11 }
12 }
android模拟点击
4.临时打桩构造函数
⽤kConstruction()临时打桩构造函数,在它的作⽤域内,new出来的对象都是模拟对象。
4.1 要求
使⽤
java要使⽤ try-with-resources 语句,kotlin可使⽤use()
4.2 java⽰例
1 @RunWith(AndroidJUnit4.class)
2public class MockitoJava {
3 @Test @SmallTest
4public void testConstruction(){
5class Student { public int run() { return1;} }
6
7 assertTrue(new Student().run() == 1 );
8 try(MockedConstruction mocked = kConstruction(Student.class)){
9 Student stu = new Student();
10 assertTrue(stu.run() == 0 ); //0,not 1
11 Mockito.when(stu.run()).thenReturn(10);
12 assertTrue(stu.run() == 10 );
13 }
14 assertTrue(new Student().run() == 1 ); //ok
15 }
16 }
第8-13⾏是个临时作⽤域,使⽤了java的try-with-resources 语法
使⽤kConstruction⽣成了⼀个MockedConstruction对象。
在第8-13⾏内,new 的student对象都是模拟对象,且可打桩(第11⾏)。
第10⾏模拟对象默认是返回0值的。
4.3 kotlin⽰例
1 @Test @SmallTest
2 fun test_mocking_construction(){
3// given
4 open class Student{ fun run() = 1 fun stop() = 2}
5
6 kConstruction(Student::class.java).use {
7 val student = Student()
8 assertTrue(student.run() == 0 ) //ok
9 `when`(student.run()).thenReturn(10)
10 assertTrue(student.run() == 10)
11 }
12 assertTrue(Student().run () == 10) //failed
13 }
结果同4.2
5.kotlin 拓展库
5.1 引⼊扩展库
testImplementation "kito.kotlin:mockito-kotlin:4.0.0"
扩展库最新版本可在github上,不是在mockito官⽹上.它可能⽐mockito库更新的慢。
5.3 简单⽰例
1 @RunWith(AndroidJUnit4::class)
2class MockitoKotlin {
3 @Test @SmallTest
4 fun mockito_kotlin_test_mock(){
5 open class Student{ fun value() = 1}
6 val mock = mock<Student>{
7 on { value() } doReturn(10)
8 }
9 assertTrue(mock.value() == 10)
10
11 val spy = spy<Student>{
12 on(it.value()).thenReturn(10)
13 }
14 assertTrue(spy.value() == 10)
15 set(spy)
16 assertTrue(spy.value() == 1 )
17 }
18 @Test @SmallTest
19 fun mockito_kotlin_test_doNothing(){
20 open class Student(var v : Int = -1) {
21 fun value(){
22 println("kotlin doNothing")
23 }
24 }
25 val mock = mock<Student> {
26 doNothing().`when`(it).value()
27 }
28 mock.value()
29 verify(mock).value()
30 }
31 }
使⽤ on .. thenReturn 对应 henReturn
5.4 更多⽰例
5.4.1 mock
1 @Test
2 fun propertyClassVariable() {
3/* When */
4 propertyClassVariable = mock()
5
6/* Then */
7 expect(propertyClassVariable).toNotBeNull()
8 }
9
10 @Test
11 fun untypedVariable() {
12/* When */
13 val instance = mock<MyClass>()
14
15 expect(instance).toNotBeNull()
16 }
17
18 @Test
19 fun deepStubs() {
20 val cal: Calendar = mock(defaultAnswer = Mockito.RETURNS_DEEP_STUBS)
21 whenever(cal.time.time).thenReturn(123L)
22 expect(cal.time.time).toBe(123L)
23 }
24
25
26 @Test
27 fun testMockStubbing_lambda() {
28/* Given */
29 val mock = mock<Open>() {
30 on { stringResult() } doReturn "A"
31 }
32
33/* When */
34 val result = mock.stringResult()
35
36/* Then */
37 expect(result).toBe("A")
38 }
5.4.2 spy
1 @Test
2 fun spyInterfaceInstance() {
3/* When */
4 val result = spy(interfaceInstance)
5
6/* Then */
7 expect(result).toNotBeNull()
8 }
9
10 @Test
11 fun spyOpenClassInstance() {
12/* When */
13 val result = spy(openClassInstance)
14
15/* Then */
16 expect(result).toNotBeNull()
17 }
18
19 @Test
20 fun doReturnWithSpy() {
21 val date = spy(Date())
22 doReturn(123L).whenever(date).time
23 expect(date.time).toBe(123L)
24 }
25
26 @Test
27 fun doNothingWithSpy() {
28 val date = spy(Date(0))
29 doNothing().whenever(date).time = 5L
30 date.time = 5L
31 expect(date.time).toBe(0L)
32 }
33
34 @Test(expected = IllegalArgumentException::class)
35 fun doThrowWithSpy() {
36 val date = spy(Date(0))
37 doThrow(IllegalArgumentException()).whenever(date).time
38 date.time
39 }
40
41 @Test
42 fun doCallRealMethodWithSpy() {
43 val date = spy(Date(0))
44 doReturn(123L).whenever(date).time
45 doCallRealMethod().whenever(date).time
46 expect(date.time).toBe(0L)
47 }
48
49 @Test
50 fun doReturnWithDefaultInstanceSpyStubbing() {
51 val timeVal = 12L
52
53 val dateSpy = spy<Date> {
54 on { time } doReturn timeVal
55 }
56
57 expect(dateSpy.time).toBe(timeVal)
58 }
59
60 @Test
61 fun doReturnWithSpyStubbing() {
62 val timeVal = 15L
63
64 val dateSpy = spy(Date(0)) {
65 on { time } doReturn timeVal
66 }
67
68 expect(dateSpy.time).toBe(timeVal)
69 }
70
71 @Test
72 fun passAnyStringToSpy() {
73/* Given */
74 val my = spy(MyClass())
75
76/* When */
77 doReturn("mocked").whenever(my).foo(any()) 78
79/* Then */
80 expect(my.foo("hello")).toBe("mocked")
81 }
5.4.3 Matchers
1 @Test
2 fun anyString() {
3 mock<Methods>().apply {
4string("")
5 verify(this).string(any())
6 }
7 }
8
9 @Test
10 fun anyInt() {
11 mock<Methods>().apply {
12int(3)
13 verify(this).int(any())
14 }
15 }
16
17 @Test
18 fun anyClosedClass() {
19 mock<Methods>().apply {
20 closed(Closed())
21 verify(this).closed(any())
22 }
23 }
24
25 @Test
26 fun anyIntArray() {
27 mock<Methods>().apply {
28 intArray(intArrayOf())
29 verify(this).intArray(any())
30 }
31 }
32
33 @Test
34 fun anyClassArray() {
35 mock<Methods>().apply {
36 closedArray(arrayOf(Closed()))
37 verify(this).closedArray(anyArray())
38 }
39 }
40
41 @Test
42 fun anyNullableClassArray() {
43 mock<Methods>().apply {
44 closedNullableArray(arrayOf(Closed(), null))
45 verify(this).closedNullableArray(anyArray())
46 }
47 }
48
49 @Test
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论