android 单元测试(1)无依赖测试

 

  单元测试不适用于测试复杂的界面交互事件。后者应改用界面测试框架。

 

1.官方文档

  https://developer.android.google.cn/training/testing/unit-testing?hl=zh-cn

  https://github.com/android/testing-samples/tree/master/unit/BasicUnitAndroidTest

  https://junit.org/junit4/index.html

  https://junit.org/junit4/javadoc/latest/overview-summary.html

  https://github.com/junit-team/junit4/wiki/Getting-started   junit使用教程

  https://developer.android.google.cn/training/testing/set-up-project

  https://developer.android.google.cn/training/testing/fundamentals#complete-testing-tasks

2.使用lint

  使用lint扫出错误、警告,然后解决它们,可以先排出很多问题。

3.添加依赖项

顶级 build.gradle 文件中添加  junit:junit :

1 dependencies {
2 
3     ...
4     testImplementation 'junit:junit:4.+'
5     androidTestImplementation 'androidx.test.ext:junit:1.1.2'
6     ...
7 }

4.编写被测试类、测试代码

4.1 使用junit api测试

被测试的类:

1 class Test1 {
2 
3     fun gt(a : Int,b : Int)  = a > b
4     fun lt(a : Int,b : Int)  = a < b
5 
6 }

测试代码:

  测试的常用的语句见 junit常用语句

  android 目前使用 Java 单元测试框架 JUnit . 简单使用@Test 注解 可添加测试。见 常用注解

  如果是类用@Test,要求是可运行的类。 

  单元测试应尽量囊括与单元的所有可能的互动,包括标准互动、无效输入以及资源不可用等情况。

 1 class ExampleUnitTest {
 2     @Test
 3     fun test1_gt(){
 4         val x = 1
 5         val y = 100
 6         val test = Test1()
 7 
 8         assertTrue("failure - x greater than y",test.gt(y,x))
 9         assertFalse("failure - x not greater than y",test.lt(x,y))
10     }
11 }

测试代码的位置

其中 :

  • androidTest 目录 包括集成测试 以及仅靠 JVM 无法完成应用功能验证的其他测试。 
  • test 目录应包含在本地计算机上运行的测试,如单元测试。

4.2 使用 androidX test api测试

官方文档:

  https://developer.android.google.cn/training/testing/set-up-project

  https://developer.android.google.cn/training/testing/fundamentals#complete-testing-tasks

 

5.调试或者运行

1.测试类或者函数

  

调试或者运行后,全绿色表示全部通过。

2.运行目录中的所有测试

  右键目录  --> Run test

   

6.生成报告

 

 报告目录默认在项目根目录下,

 

7.常用的junit测试语句

https://junit.org/junit4/index.html

assert系列

void assertTrue(String message, boolean condition)

断言条件为真,若非:抛出AssertionError异常(内容为message)

void assertTrue(boolean condition)

断言条件为真,若非,抛出AssertionError异常

void assertFalse(String message, boolean condition)

断言条件为假,若非:抛出AssertionError异常(内容为message)

void assertFalse(boolean condition)

断言条件为假,若非:抛出AssertionError异常

void assertEquals(String message, Object expected, Object actual)

断言expected与actual相等,若非:抛出AssertionError异常(message)

当两个都是空时,认为相等。

void assertEquals(Object expected, Object actual)

断言expected与actual相等,若非:抛出AssertionError异常

当两个都是空时,认为相等。

void assertNotEquals(String message, Object unexpected, Object actual)

断言不等,若非:抛出AssertionError异常(message)

当两个都是空时,认为相等。

void assertNotEquals(Object unexpected, Object actual)

断言不等,若非:抛出AssertionError异常

当两个都是空时,认为相等。

void assertNotEquals(String message, long unexpected, long actual)

断言不等,若非:抛出AssertionError异常(message)

两个都是long类型

void assertNotEquals(long unexpected, long actual)

断言unexpected与actual不等,若非:抛出AssertionError异常

两个都是long类型

... ...
assert数组  

void assertArrayEquals(boolean[] expecteds, boolean[] actuals)

断言相等,若非:抛出AssertionError异常

当两个都是空时,认为相等。

void assertArrayEquals(String message, boolean[] expecteds, boolean[] actuals)

断言相等,若非:抛出AssertionError异常(message)

当两个都是空时,认为相等。

类似的还有Object[]、byte[]、char[]、short[]、int[]、long[]、double[]、float[] 

fail系列

void fail(String message)

Fails a test with the given message.

void fail(String message) 

Fails a test with the given message.

还有一些私有的,不能直接调用的:failEquals、failNotEquals、failNotNull、failNotSame、failSame

8.常用注解

@Test

  标注测试类或者测试方法,如

1 @Test
2 fun addition_isCorrect() {
3     assertEquals(4, 2 + 2)
4 }

@Test(timeout=1000) 

  设置测试超时时间,到时会自动失败,单位是毫秒。

1     @Test(timeout = 3000)
2     fun test_timeout(){
3         var time = 1
4         while (time++ < 5){
5             println("time = $time")
6             Thread.sleep(1000 * 1)
7         }
8         println("test_timeout finished")
9     }

  结果:

@Ignore(string)

  忽略一个测试,无法运行或者调试,用在@Test之前,如

1     @Ignore("Test is ignored as a demonstration")
2     @Test
3     fun test_ignore(){
4         println("test_ignore")
5     }

@RunWith 

  它们只用来注解类,不注解函数。

  JUnit用例都是在Runner(运行器)来执行的,用runwith指定运行器,默认的是BlockJUnit4ClassRunner,还有常用的Suite、Categories等,如:

 1     @RunWith(BlockJUnit4ClassRunner::class)
 2     class TestB{
 3         @Test
 4         fun testB_f1(){
 5             println("testB . f1")
 6         }
 7     }
 8 
 9     @RunWith(Suite::class)
10     class TestC{
11         @Test
12         fun test_runwith(){
13             println("TestC . test_runwith")
14         }
15     }

  也可以自己定义Runner。

@Suite.SuiteClasses

  注解类,与@RunWith(Suite.class)一直使用,指定要测试的类,类中的未标注ignore的用例都被执行。

 1     class Suite1{
 2         @Test
 3         fun f1(){
 4             println("Suite1 . f1")
 5         }
 6         @Test
 7         fun f2(){
 8             println("Suite1 . f2")
 9         }
10         @Ignore("todo")
11         @Test
12         fun f3(){
13             println("Suite1 . ignore f3")
14         }
15     }
16 
17     class Suite2{
18         @Test
19         fun f1(){
20             println("Suite2 . f1")
21         }
22         @Test
23         fun f2(){
24             println("Suite2 . f2")
25         }
26         @Test
27         fun f3(){
28             println("Suite2 . f3")
29         }
30     }
31 
32     @RunWith(Suite::class)
33     @Suite.SuiteClasses(Suite1::class,Suite2::class)
34     class TestC{
35         @Test
36         fun test_runwith(){
37             println("TestC . test_runwith")
38         }
39     }

  其中Suite1.f3会被忽略,结果如下:

@Category 与 @IncludeCategory、@ExcludeCategory

  给测试分类

 1     //Category
 2     interface Category1
 3     interface Category2
 4 
 5     class A{
 6         @Test
 7         fun a() {
 8             println("A.a()")
 9         }
10         @Category(Category2::class)                 //Category2
11         @Test
12         fun b() {
13             println("A.b()")
14         }
15     }
16 
17     @Category(Category1::class,Category2::class)    //Category1,Category2
18     class B{
19         @Test
20         fun c() {
21             println("B.c()")
22         }
23     }
24 
25     @Test
26     @Category(Category1::class,Category2::class)
27     fun test_Category(){
28 
29     }
30 
31     @RunWith(Categories::class)
32     @Categories.IncludeCategory(Category1::class)
33     @Suite.SuiteClasses(A::class,A::class)
34     class CategoryInclude{
35         @Test
36         fun main(){
37             println("CategoryInclude")
38         }
39     }
40 
41     @RunWith(Categories::class)
42     @Categories.ExcludeCategory(Category2::class)
43     @Suite.SuiteClasses(A::class,B::class)
44     class CategoryExclude{
45         @Test
46         fun main(){
47             println("CategoryExclude")
48         }
49     }
  • 第2、3行定义了两个分类Category1与Category2
  • A.b()属于Category2
  • B属于Category1和Category2
  • 第34行类CategoryInclude测试结果为  B.c()
  • 第44行类CategoryExclude测试结果为  A.a()

其它

  如 @BeforeClass、@Before、@After、@AfterClass 等,义如其名。

 

posted @ 2021-10-08 19:29  f9q  阅读(400)  评论(0编辑  收藏  举报