https://mockk.io/
presenter
https://www.jianshu.com/p/899e80120071
https://blog.csdn.net/hard_working1/article/details/105613362
https://juejin.cn/post/6877824384694747143
LIST COMPARE 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 @Test fun `compare to list`() { val actual = listOf("a" , "b" , "c" ) val expected = listOf("a" , "b" , "c" ) Assert.assertThat(actual , CoreMatchers.`is `(expected)) Assert.assertThat(actual , CoreMatchers.hasItems("b" )) Assert.assertThat(actual , Matchers.hasSize(3 )) Assert.assertThat(actual .size, CoreMatchers.`is `(3 )) Assert.assertThat(actual , Matchers.contains("a" , "b" , "c" )) Assert.assertThat(actual , IsIterableContainingInAnyOrder.containsInAnyOrder("c" , "b" , "a" )) Assert.assertThat(actual , CoreMatchers.not(IsEmptyCollection.empty())) }
https://stackoverflow.com/questions/46788032/compare-2-liststring-if-they-contain-same-elements-in-any-order-junit-asset https://mkyong.com/unittest/junit-how-to-test-a-list/
http://hamcrest.org/JavaHamcrest/distributables
mock与spy的区别 1 2 3 4 5 6 7 8 9 10 11 @Test public void mockDifSpy() throws Exception { User userMock = mock(User.class); userMock.setNumber(2); int num = userMock.getNumber(); System.out.println("mock返回 "+num); User userSpy = spy(User.class); userSpy.setNumber(5); System.out.println("spy返回 "+userSpy.getNumber()); }
mock返回 0 spy返回 5
mock : 如果不指定mock方法的特定行为,一个mock对象的所有非void方法都将返回默认值:int、long类型方法将返回0,boolean方法将返回false,对象方法将返回null等等;而void方法将什么都不做。
spy : spy对象的方法默认调用真实的逻辑,mock对象的方法默认什么都不做,或直接返回默认值。
https://www.jianshu.com/p/0a8bbfe6cba2
实例讲解
http://blog.csdn.net/qq_17766199/article/details/78450007 https://github.com/ChrisZou/android-unit-testing-tutorial https://github.com/qingmei2/Sample_AndroidTest
一个Android项目搞定所有主流架 mvp生成模板https://www.diycode.cc/topics/309 https://github.com/boredream/DesignResCollection
Robolectric http://robolectric.org/getting-started/
Robolectric
1 2 3 4 5 6 7 8 9 testImplementation "org.robolectric:robolectric:3.8" android { testOptions { unitTests { includeAndroidResources = true } } }
Mockk Constructor mocks verify失败
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 @Test fun `mock different constuctor`() { mockkConstructor(MockCls::class ) every { constructedWith<MockCls>().add(1 ) } returns 2 every { constructedWith<MockCls>(OfTypeMatcher<String>(String::class )).add (2 ) } returns 3 every { constructedWith<MockCls>(EqMatcher(4 )).add(any()) } returns 4 assertEquals(1 , MockCls().add(1 )) assertEquals(3 , MockCls("2" ).add(2 )) assertEquals(4 , MockCls(4 ).add(7 )) verify { constructedWith<MockCls>().add(1 ) constructedWith<MockCls>(EqMatcher(4 )).add(7 ) }
为无返回值的方法分配默认行为 把 every {…} 后面的 Returns 换成 just Runs ,就可以让 MockK 为这个没有返回值的方法分配一个默认行为。
1 2 3 4 5 6 7 @Test fun testGetGoods () { val goods = presenter!!.getGoods(1 ) every { view.showLoading() } just Runs verify { view.showLoading() } assertEquals(goods.name, "纸巾" ) }
为所有模拟对象的方法分配默认行为 1 2 3 4 @Before fun setUp () { MockKAnnotations.init (this , relaxed = true ) }
Annotation 只要在 @Before
方法裡面加上 MockKAnnotations.init(this)
就能在外面用 Annotation 的方式 Mock 物件。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 class KidAnnotationTest { @MockK lateinit var mother: Mother lateinit var kid: Kid @Before fun setUp () { val mother = mockk<Mother>() MockKAnnotations.init (this ) kid = Kid(mother) } @Test fun wantMoney () { every { mother.giveMoney() } returns 30 kid.wantMoney() assertEquals(30 , kid.money) } }
https://proandroiddev.com/understanding-unit-tests-for-android-in-2021-71984f370240
https://medium.com/joe-tsai/mockk-%E4%B8%80%E6%AC%BE%E5%BC%B7%E5%A4%A7%E7%9A%84-kotlin-mocking-library-part-2-4-4be059331110
https://tngdigital.yuque.com/tngd-mobile/key-battle/wldcgt