Jacoco là một công cụ check test coverage có từ khá lâu rồi, chúng ta thường config jacoco trong một file .gradle và thêm vào build.gradle của module app khi muốn check coverage.
Gần đây việc gradle sử dụng kotlin trong gradle kts giúp chúng ta có thể config dễ dàng hơn với code kotlin thay vì groovy như trước.
Tuy nhiên hiện tại gradle chưa support việc thêm jacoco từ file gradle.kts riêng biệt nên chúng ta sẽ cần thêm code jacoco vào file gradle.kts của module cần check coverage.
Dưới đây là một ví dụ về việc config jacoco cho gradle kts mà các bạn có thể tham khảo
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 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 | plugins <span class="token punctuation">{</span> <span class="token operator">..</span><span class="token punctuation">.</span> jacoco <span class="token punctuation">}</span> jacoco <span class="token punctuation">{</span> toolVersion <span class="token operator">=</span> <span class="token string">"0.8.5"</span> <span class="token punctuation">}</span> <span class="token comment">/** There are two ways to see test result: * FIRST * To run this test coverage with buildTypes: Debug; Flavor: Dev * use command: ./gradlew clean testDevDebugUnitTestCoverage * * See result at: * app/build/reports/jacoco/testDevDebugUnitTestCoverage/html/index.html * * SECOND: * - Click Gradle on the right menu of Android Studio IDE * - At Project name, expand "app", expand "Tasks", expand "coverage" * - Run any test you want */</span> project<span class="token punctuation">.</span><span class="token function">afterEvaluate</span> <span class="token punctuation">{</span> <span class="token comment">// Grab all build types and product flavors</span> <span class="token keyword">val</span> buildTypeNames<span class="token operator">:</span> List<span class="token operator"><</span>String<span class="token operator">></span> <span class="token operator">=</span> android<span class="token punctuation">.</span>buildTypes<span class="token punctuation">.</span><span class="token function">map</span> <span class="token punctuation">{</span> it<span class="token punctuation">.</span>name <span class="token punctuation">}</span> <span class="token keyword">val</span> productFlavorNames<span class="token operator">:</span> ArrayList<span class="token operator"><</span>String<span class="token operator">></span> <span class="token operator">=</span> <span class="token function">ArrayList</span><span class="token punctuation">(</span>android<span class="token punctuation">.</span>productFlavors<span class="token punctuation">.</span><span class="token function">map</span> <span class="token punctuation">{</span> it<span class="token punctuation">.</span>name <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token comment">// When no product flavors defined, use empty</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>productFlavorNames<span class="token punctuation">.</span><span class="token function">isEmpty</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> productFlavorNames<span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span><span class="token string">""</span><span class="token punctuation">)</span> productFlavorNames<span class="token punctuation">.</span><span class="token function">forEach</span> <span class="token punctuation">{</span> productFlavorName <span class="token operator">-></span> buildTypeNames<span class="token punctuation">.</span><span class="token function">forEach</span> <span class="token punctuation">{</span> buildTypeName <span class="token operator">-></span> <span class="token keyword">val</span> sourceName<span class="token operator">:</span> String <span class="token keyword">val</span> sourcePath<span class="token operator">:</span> String <span class="token keyword">if</span> <span class="token punctuation">(</span>productFlavorName<span class="token punctuation">.</span><span class="token function">isEmpty</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> sourcePath <span class="token operator">=</span> buildTypeName sourceName <span class="token operator">=</span> buildTypeName <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span> sourcePath <span class="token operator">=</span> <span class="token string">"<span class="token interpolation"><span class="token delimiter variable">${</span>productFlavorName<span class="token delimiter variable">}</span></span>/<span class="token interpolation"><span class="token delimiter variable">${</span>buildTypeName<span class="token delimiter variable">}</span></span>"</span> sourceName <span class="token operator">=</span> <span class="token string">"<span class="token interpolation"><span class="token delimiter variable">${</span>productFlavorName<span class="token delimiter variable">}</span></span><span class="token interpolation"><span class="token delimiter variable">${</span>buildTypeName<span class="token punctuation">.</span><span class="token function">capitalize</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token delimiter variable">}</span></span>"</span> <span class="token punctuation">}</span> <span class="token keyword">val</span> testTaskName <span class="token operator">=</span> <span class="token string">"test<span class="token interpolation"><span class="token delimiter variable">${</span>sourceName<span class="token punctuation">.</span><span class="token function">capitalize</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token delimiter variable">}</span></span>UnitTest"</span> <span class="token comment">// Create coverage task of form 'testFlavorTypeCoverage' depending on 'testFlavorTypeUnitTest'</span> task<span class="token operator"><</span>JacocoReport<span class="token operator">></span><span class="token punctuation">(</span><span class="token string">"<span class="token interpolation"><span class="token delimiter variable">${</span>testTaskName<span class="token delimiter variable">}</span></span>Coverage"</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">//where store all test to run follow second way above</span> group <span class="token operator">=</span> <span class="token string">"coverage"</span> description <span class="token operator">=</span> <span class="token string">"Generate Jacoco coverage reports on the <span class="token interpolation"><span class="token delimiter variable">${</span>sourceName<span class="token punctuation">.</span><span class="token function">capitalize</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token delimiter variable">}</span></span> build."</span> <span class="token keyword">val</span> excludeFiles <span class="token operator">=</span> <span class="token function">arrayListOf</span><span class="token punctuation">(</span> <span class="token string">"**/R.class"</span><span class="token punctuation">,</span> <span class="token string">"**/R$*.class"</span><span class="token punctuation">,</span> <span class="token string">"**/BuildConfig.*"</span><span class="token punctuation">,</span> <span class="token string">"**/Manifest*.*"</span><span class="token punctuation">,</span> <span class="token string">"**/*Test*.*"</span><span class="token punctuation">,</span> <span class="token string">"android/**/*.*"</span><span class="token punctuation">,</span> <span class="token string">"**/*_MembersInjector.class"</span><span class="token punctuation">,</span> <span class="token string">"**/Dagger*Component.class"</span><span class="token punctuation">,</span> <span class="token string">"**/Dagger*Component<span class="token interpolation variable">$Builder</span>.class"</span><span class="token punctuation">,</span> <span class="token string">"**/*_*Factory.class"</span><span class="token punctuation">,</span> <span class="token string">"**/*ComponentImpl.class"</span><span class="token punctuation">,</span> <span class="token string">"**/*SubComponentBuilder.class"</span><span class="token punctuation">,</span> <span class="token string">"**/*Creator.class"</span><span class="token punctuation">,</span> <span class="token string">"**/*Application*.*"</span><span class="token punctuation">,</span> <span class="token string">"**/*Activity*.*"</span><span class="token punctuation">,</span> <span class="token string">"**/*Fragment*.*"</span><span class="token punctuation">,</span> <span class="token string">"**/*Adapter*.*"</span><span class="token punctuation">,</span> <span class="token string">"**/*Dialog*.*"</span><span class="token punctuation">,</span> <span class="token string">"**/*Args*.*"</span><span class="token punctuation">,</span> <span class="token string">"**/*Companion*.*"</span><span class="token punctuation">,</span> <span class="token string">"**/*Kt*.*"</span><span class="token punctuation">,</span> <span class="token string">"**/com/example/moviedb/di/**/*.*"</span><span class="token punctuation">,</span> <span class="token string">"**/com/example/moviedb/ui/navigation/**/*.*"</span><span class="token punctuation">,</span> <span class="token string">"**/com/example/moviedb/ui/widgets/**/*.*"</span> <span class="token punctuation">)</span> <span class="token comment">//Explain to Jacoco where are you .class file java and kotlin</span> classDirectories<span class="token punctuation">.</span><span class="token function">setFrom</span><span class="token punctuation">(</span> <span class="token function">fileTree</span><span class="token punctuation">(</span><span class="token string">"<span class="token interpolation"><span class="token delimiter variable">${</span>project<span class="token punctuation">.</span>buildDir<span class="token delimiter variable">}</span></span>/intermediates/classes/<span class="token interpolation"><span class="token delimiter variable">${</span>sourcePath<span class="token delimiter variable">}</span></span>"</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">exclude</span><span class="token punctuation">(</span> excludeFiles <span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token function">fileTree</span><span class="token punctuation">(</span><span class="token string">"<span class="token interpolation"><span class="token delimiter variable">${</span>project<span class="token punctuation">.</span>buildDir<span class="token delimiter variable">}</span></span>/tmp/kotlin-classes/<span class="token interpolation"><span class="token delimiter variable">${</span>sourceName<span class="token delimiter variable">}</span></span>"</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">exclude</span><span class="token punctuation">(</span> excludeFiles <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token keyword">val</span> coverageSourceDirs <span class="token operator">=</span> <span class="token function">arrayListOf</span><span class="token punctuation">(</span> <span class="token string">"src/main/java"</span><span class="token punctuation">,</span> <span class="token string">"src/<span class="token interpolation variable">$productFlavorName</span>/java"</span><span class="token punctuation">,</span> <span class="token string">"src/<span class="token interpolation variable">$buildTypeName</span>/java"</span> <span class="token punctuation">)</span> additionalSourceDirs<span class="token punctuation">.</span><span class="token function">setFrom</span><span class="token punctuation">(</span><span class="token function">files</span><span class="token punctuation">(</span>coverageSourceDirs<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token comment">//Explain to Jacoco where is your source code</span> sourceDirectories<span class="token punctuation">.</span><span class="token function">setFrom</span><span class="token punctuation">(</span><span class="token function">files</span><span class="token punctuation">(</span>coverageSourceDirs<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token comment">//execute file .exec to generate data report</span> executionData<span class="token punctuation">.</span><span class="token function">setFrom</span><span class="token punctuation">(</span><span class="token function">files</span><span class="token punctuation">(</span><span class="token string">"<span class="token interpolation"><span class="token delimiter variable">${</span>project<span class="token punctuation">.</span>buildDir<span class="token delimiter variable">}</span></span>/jacoco/<span class="token interpolation"><span class="token delimiter variable">${</span>testTaskName<span class="token delimiter variable">}</span></span>.exec"</span><span class="token punctuation">)</span><span class="token punctuation">)</span> reports <span class="token punctuation">{</span> xml<span class="token punctuation">.</span>isEnabled <span class="token operator">=</span> <span class="token boolean">true</span> html<span class="token punctuation">.</span>isEnabled <span class="token operator">=</span> <span class="token boolean">true</span> <span class="token punctuation">}</span> <span class="token function">dependsOn</span><span class="token punctuation">(</span>testTaskName<span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> |
Các bạn có thể tham khảo source code ở đây https://github.com/dangquanuet/The-Movie-DB-Kotlin/blob/develop/app/build.gradle.kts#L29
Sau đó các bạn có thể tiến hành chạy test coverage như bình thường với jacoco trước đây là qua command line hay là gradle task.
Bài lần này đến đây là kết thúc, hẹn gặp lại các bạn sau