首先,Spock 的測試程式碼需要使用 Groovy 語言來撰寫,所以 build.gradle 中要先引用 Groovy 的 Gradle Plugin。第一步要在 Root 的 build.gradle 中增加以下內容:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
buildscript { | |
... | |
dependencies { | |
... | |
classpath 'org.codehaus.groovy:groovy-android-gradle-plugin:1.1.0' | |
} | |
} |
第二步是在要使用 Groovy 的專案 build.gradle 中增加 apply plugin: 'groovyx.android’ 的內容,讓 Gradle 可以正確地識別 Groovy 所寫的程式。
第三步要設定在封裝 Apk 的過程中被排除的檔案:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
packagingOptions { | |
exclude 'META-INF/services/org.codehaus.groovy.transform.ASTTransformation' | |
exclude 'META-INF/services/org.codehaus.groovy.runtime.ExtensionModule' | |
} |
完成以上的工作就可以設定 Dependencies 以便在撰寫程式時可以引用到 Spock Framework 裡的 Class。但是光只有 Spock 也只能對一般的 Class 進行測試,如果要測試 Android 元件,牽涉到 Context 的問題,還是要使用官方的 Espresso 或是 Robolectric。
Espresso 的問題不大,只要把 Java 的寫法改成 Groovy 套到 Spock 的 Class 結構裡就行了。Robolectric 則是要改為引用另一個套件:Robospock,依照 RoboSpock 的官方文件的說明,就可以順利的使用 Spock 來測試 Android 的元件。RoboSpock 就已經有引用 Robolectric 所以自己的 build.gradle 並不需要再設定一次。只是必須受限於 RoboSpock 建置時所設定的 Robolectric 版本,不一定能使用最新版的 Robolectric。
最後一個要注意的事項是,Espresso 在執行前是要經過實際封裝 Apk 的過程,所以 Groovy 在引用時要使用特別為 Android 開發的版本 - org.codehaus.groovy:groovy:2.4.7:grooid,否則很容易會出現超出 64K 的問題。
以下是完整的 build.gradle 的示範內容:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
apply plugin: 'com.android.application' | |
apply plugin: 'groovyx.android' | |
android { | |
compileSdkVersion 24 | |
buildToolsVersion "25.0.0" | |
defaultConfig { | |
applicationId "com.example.sampleapp” | |
minSdkVersion 9 | |
targetSdkVersion 24 | |
versionCode 1 | |
versionName "1.0" | |
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" | |
} | |
testOptions { | |
unitTests.returnDefaultValues = true | |
} | |
packagingOptions { | |
exclude 'META-INF/services/org.codehaus.groovy.transform.ASTTransformation' | |
exclude 'META-INF/services/org.codehaus.groovy.runtime.ExtensionModule' | |
} | |
buildTypes { | |
release { | |
minifyEnabled false | |
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' | |
} | |
} | |
} | |
dependencies { | |
compile fileTree(include: ['*.jar'], dir: 'libs') | |
testCompile 'org.codehaus.groovy:groovy-all:2.4.7' | |
testCompile 'org.spockframework:spock-core:1.0-groovy-2.4' | |
testCompile 'org.robospock:robospock:1.0.1' | |
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { | |
exclude group: 'com.android.support', module: 'support-annotations' | |
}) | |
androidTestCompile('com.android.support.test.espresso:espresso-contrib:2.2.2', { | |
exclude group: 'com.android.support', module: 'support-annotations' | |
}) | |
androidTestCompile 'org.codehaus.groovy:groovy:2.4.7:grooid' | |
androidTestCompile('org.spockframework:spock-core:1.0-groovy-2.4') { | |
exclude group: 'org.codehaus.groovy' | |
exclude group: 'junit' | |
} | |
} |
撰寫 Spock 測試前要先手動在 androidTest 或是 test 目錄下增加 groovy 的目錄,其下再依據所屬的 Package 產生路徑結構。
最後,由於相容性的關係,在編譯的過程中會持續出現以下的訊息,但實際操作時並沒有阻擋或影響到測試程式的執行,所以可以忽略、不用理會。
:module:transformClassesWithDexForDebugAndroidTest AGPBI: {"kind":"error","text":"warning: Ignoring InnerClasses attribute for an anonymous inner class","sources":[{}]} AGPBI: {"kind":"error","text":"(groovyjarjarantlr.TokenStreamRewriteEngine$1) that doesn\u0027t come with an","sources":[{}]} AGPBI: {"kind":"error","text":"associated EnclosingMethod attribute. This class was probably produced by a","sources":[{}]} AGPBI: {"kind":"error","text":"compiler that did not target the modern .class file format. The recommended","sources":[{}]} AGPBI: {"kind":"error","text":"solution is to recompile the class from source, using an up-to-date compiler","sources":[{}]} AGPBI: {"kind":"error","text":"and without specifying any \"-target\" type options. The consequence of ignoring","sources":[{}]} AGPBI: {"kind":"error","text":"this warning is that reflective operations on this class will incorrectly","sources":[{}]} AGPBI: {"kind":"error","text":"indicate that it is *not* an inner class.","sources":[{}]} AGPBI: {"kind":"error","text":"warning: Ignoring InnerClasses attribute for an anonymous inner class","sources":[{}]} AGPBI: {"kind":"error","text":"(groovyjarjarantlr.build.ANTLR$1) that doesn\u0027t come with an","sources":[{}]} AGPBI: {"kind":"error","text":"associated EnclosingMethod attribute. This class was probably produced by a","sources":[{}]} AGPBI: {"kind":"error","text":"compiler that did not target the modern .class file format. The recommended","sources":[{}]} AGPBI: {"kind":"error","text":"solution is to recompile the class from source, using an up-to-date compiler","sources":[{}]} AGPBI: {"kind":"error","text":"and without specifying any \"-target\" type options. The consequence of ignoring","sources":[{}]} AGPBI: {"kind":"error","text":"this warning is that reflective operations on this class will incorrectly","sources":[{}]} AGPBI: {"kind":"error","text":"indicate that it is *not* an inner class.","sources":[{}]} AGPBI: {"kind":"error","text":"warning: Ignoring InnerClasses attribute for an anonymous inner class","sources":[{}]} AGPBI: {"kind":"error","text":"(groovyjarjarantlr.debug.misc.ASTFrame$1) that doesn\u0027t come with an","sources":[{}]} AGPBI: {"kind":"error","text":"associated EnclosingMethod attribute. This class was probably produced by a","sources":[{}]} AGPBI: {"kind":"error","text":"compiler that did not target the modern .class file format. The recommended","sources":[{}]} AGPBI: {"kind":"error","text":"solution is to recompile the class from source, using an up-to-date compiler","sources":[{}]} AGPBI: {"kind":"error","text":"and without specifying any \"-target\" type options. The consequence of ignoring","sources":[{}]} AGPBI: {"kind":"error","text":"this warning is that reflective operations on this class will incorrectly","sources":[{}]} AGPBI: {"kind":"error","text":"indicate that it is *not* an inner class.","sources":[{}]}
0 意見:
張貼留言