不会测验的开发不是好开发——鲁迅
一直以来,关于如何写测验代码的相关内容资源都比较少,之前在优达学城看到了这部分的视频,但由于没有中文字幕,对有些小伙伴或许不太友好。因而我决议将其整理成c 1 s系列文章,那么就从认识 test 开始吧
本文内容来自 Udacity Advanced Android with Kotlin-LesP v Xson 10-5.1 Testing:Basics
结构
作为 Android 开发者咱们知道在 Android StudC ? 1 z q eio 的 And( M t Z B Sroid 视图中有三部分代码
- app 的逻辑代码(main source set)
- androidTest 代码
- local te} % q @ _ X & .st 代码
test 代码知道一切的 main source set 中的0 V B % A代码,因而能够测验这些类。但是 app 代码不知道 test 中的代码,而且 androidTest 和 test 都不知道对方的存在。事实上,当你构建出 a5 } j 8 D _ j E .pk 并提交运用商场时,测验代码并没有包括在内
依靠引证
下面符号的依靠 运用了 test 的引证办法 testImplementation
和 androidTestImplementat& g 3ion
留意:这些 test 代码不会打包到最终的 apk 文件} J ) X l ^ e中
testImplementation
引证的 JUnit
依靠只能在 test source set 中运用,这种依靠规模的限制是 Gradle
完成的
简略总结下:
- 三种 source sets:
mT Q I , 0 n a } 9ain
,test
,androidTest
- 测验代码能访问 app 代码
- app 代码 不能 访问测验代码
- 测验不会被打入到 Apk 中
- 依靠规模包括:
testImplementation
和androidTestImplementation
运转榜首个 test
咱们打开 test source2 m r Y ^ set ,看到m J : & I z f @其中有一个 ExampleUnitTestI M 0 Z
能够看到其内部只要一个 addition_isCorrect()
办法
有F ^ H P ; 3 c两个要素使它成为一个 test:
- 运用了
@Test
注解 - 它存在于两个 tes2 V &t source set 之一
有了这两个要素,这个办法就能够Y D y b 独立的作为 test0 : A d & ~ 运转
本示例 test 测验的内容在第 15 行,它被称之为断语(assertion
)
断语是 test 的核心内容,它查看你的代码或许 app 行为是否符合你的预期
本示例中,断语查看 4 是否等g f J ,于 2 + 2
按照规则,您需求将你的 预期成果 传入到 expectedJ U D ? % Q 参数中,将 实际成果 传入到 actual 参数中
@Test
注解和断语语句都是 JUnit
下的
关于 JUnit
的更详细的的信息,请移步 官方文档
让咱们开始运转一下这个 test,右击该办法,点击 Run
紧接着,Run 窗口会呈现
能够看到该窗口显示了 test 的信息,显示出 test 是否经过以及有多少 test 经过
下面咱们尝试一个 test 不经过的状况,咱们加入一个断语,如下所示
这{ J } W B p e次咱们点击 Run 窗口的绿色按钮来运转 test
咱们能够看到,即使只要一个断语失利,整个 test 失利了
窗口指出了预期的成果) & @ F f为 5,而实际的成果为 4,而且下边符号处p / C M b = I过错发生在第 15 行,能够看到这的确是个 b[ % [ f w 2ug
处理好 bug ,咱们再次运转 test 。这次咱们运用一个不相同的办法
下面介绍一些其他运转 test 的办法
能够右击类名挑选 Run 选项
也能够在左侧视图中右击 test source set 挑选 Run 按钮,该办法会运转= F x / S一切 test。在顶部能够切换要运转的 test ,点击绿色按钮能够运转t , q | } d。也可切换回U T n app
androidTest VS test
下面咱们来比照一下 androidTe4 2 n e X ust
和 test
test | androidTest |
---|---|
Local Tests | Instrumented Tests |
Local machineb d X X ? JVM | Real or e ` J 3 6 v 7 l 4mulate[ % xd deviceT U } {s |
Faster | Slq O Q &ower |
咱们来运转一个 androidTest
,能够看到启动了模拟器
写一个 test
首要咱们针对一个功用来创建 test,如图所示,存在一个 getForkAndOriginRepoStats()
办法用于获取 fork 库房和原始库房的数据E u J Z A / d )并返回 StatsResult
,其中 StatsResult
榜首个参数为 fork 项目的~ V d百分比,第二个参数为原始项目的百分比。咱们调用 Generate
,选中 test 选项,在弹出框中挑选 JUnit4
,点击 OK 并挑选存放在 local test 中。这样咱们就创建了一个 test
接下来咱们编写 test 。能够看到自动创建出的 test 途径与 app code 中的代码途径的包名是对应的。咱们先测验项目列表只要一个 item,R 4 R R [而且没有 fork ,然后核算 fork 项目的百分比和原始项目的百分比。理论上讲,fork 项目的百U O x B & X B [ M分比为b ( 3 ] d C @ q ^ 0 ,而原始项目的百分比为 100%,代码如下图所示,咱们编写结束后点击运转
能够看到测验经过
这是一个正常流程,咱们还需求测验异常的流程,比方 repos 为 emp: P G T ! % t / mty list 或许 repos 变量本身为 null
能够看到咱们的代码中没有针对 list 为 empty 或 null 做判别,所以导致了空指针,之后咱们修正代码后即可经过测验
事实上,咱们上面的编码流程叫做 Test Driven Development(TDD) 有关 TDD
的更多信息,能够移步W / m D # m Test-Driven Development on Android with the A* p $ a j & Z ^ndroid Testing Support Library (Google I/O ’17)
让你的 test 更具可读性
与写一般) ( K代码相同,您需求让您的 test 代码更具可读性,能够从三个方向入手
- 优异的命名
- Given/When/Then
- 借助断语库
优异的命名
首要咱们来谈谈命名,咱们知道 test 办法运用 @Test 注解符号,理论上办法名能够随意命名,但随意的命名会导致可读性的下降,因而需求一些特定的命名标准
测验模块C 9 I_ 动作或输入_ 成果状况
例如上面的例} – n 3 Q 5 g子咱们的命名为:getForkAndOriginRepoStats_noForked_returnHundredZero
榜首部分显示咱们要测验的是 getForkAndOriginRepoStats()
办法,第二部分代表咱们需求的是没有 for2 4 0 [k 库r ( 2 O 2 x房的数据源,第三部分是成果的状况,0%
Given/When/Then
说完了命名咱们来谈谈 Given/When/Then
测验的根本结构是 Given X,When Y,Then Z
还是上面的例子
- Given 为你的测验逻辑供给数据源
- When 是你的实际操 U = d A K作
- Then 查看 test 是否经过
借助断语库
上面示例最终的断语代码让人看着很别扭,咱们能够借助断语库来提高这部分的可读性
// 之前
assertEquals(result.forkPercent, 0f)
// 之后
assk b - t b # ;ertThat(result.forkPercent, `is`(0f))
下面的语句就W t 像人类的一句话,翻译下来就是 断语 forkPercent 是 0f
这样的写法需求引进一个库 Hamcrest
testImplementation , % f 3 E"org.hc S E f ] )amcrest:hamcrest-all:1.3"
留意:由于
is
是 kotlin 中的关键字,因而运用 `is` 来转义
常用的断语库
- Hamcrest
- Truth Library
测验规模
测验规模指一个 test 测验多少代码
例如自动化测验根据测验规模能够分为
- Unit Tesc Y Q @ Xts(单元测验)
- InP } & $ X / ?tegration Tests(拼装测验% 5 ! V d } x : z)
- End to end Tests(端到端测验)
您的测U R 9 | = #验战略需求掩盖到一切的类型
Unit Tests
上面的示例咱们已经写过了 Unit TeS G 2sts
- 规模是单个o _ j 3 G ] r办法或类
- 帮助查明失利原因
- 应该运转的很快,通常是本地测验
- 低保真度
他们的规模是单个的办法或类
假如 Unit Tests
失利了,您知道您的代码在哪里出了问题。由于它聚集于很小一段代码
Unit Tests
也意味着能够快速运转,由于您频频地修正代码会使得它会频频的运转,因而需求速度Q 5 I ) l 2 d。Unit Tests
通常是本地测验
它们有较低的保真度,由于实际世界您的 app 要执行许多代码而不仅仅是一个办法或许类
Unit Tests
就像查看一个y & 7 H 9链条的每个环节是否能够正常运转
但它不查看这些环节组合在一起是否能够运转,为此您需求 I$ 0 # T =ntegration Tests
Integration Tests
I^ 0 D # C L ] Wntegration Tests
具有更大的规模
- 规模是几个类或单个功用
- 保证几个– f ? $ _ ` 类共同运转
- 能够运用本地测验或机器测验
就像 Integration
这个词相同: ] O E,Integration Tests
整合一些类保证他们组合起来的表现符合预期
构建 Integration Tests
的办法是让他们测验单个功用,就像获取指定用户的 Github
库房
与 Unit Tests
相比,Integration Tests
有着更大的规模,但他们仍运转的很快而且有着很好的保真度
根据具体状况来判别运用本地z G n y R y D测验还是机器测验,例如假如您写的 Integration Tests
触及到了 UI 组件,那么您需求运用真机来测验了
End to end Tests
第三种类型是 End to end Tests
,该测验将一些列功用组合起来一起运转
- 规模是 app 的大部分
- 高保真度
- 将 app 作为全体来测验
- 接近真实地运用,应该运用设备测验V L { t ~ v
End to end Tests
测验 app 的大部分,它非常接近真实地运用,因而速度上会比较慢
它有着最高的保真度并保证您的运用k p A Q I = +作为一个全体运# u Q . . 0转
这 A ( N些测验应该运用设_ 9 k备测验
测验比重
引荐的测验份额是 70% 的单元测验,20% 的d v q拼装测验,以及10% 的端到端测验
您能否轻松地在各个部分测验您的 app 取决于您的 app 运用的结构
例如,您的运用将一切逻辑都放置在一个 activity 的大的办法中,您或许能够写出端到端测验,但单元测验和拼装测验则写不出来
一个更好的架构应该B O – T + ; ?将运用的逻辑拆分为多个办法和类,这允许每部分能够独立的测验
对于单元测验,您能够测验 ViewModel
,Repository
以及 DAO
对于拼装测R r %验,您能够组合测验 fragment
和 ViewModel
,或许您能够测验整个数据库代码
端到端测验会测验整个运用
关于@ M c E q测验的原理,可移步 官方文档
test 的 codelab
关于我
我是 FlU 1 m R oy_with24
- 掘金
- 简书
- Github