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 等,義如其名。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM