Firebase测试实验室为/jacoco.exec抛出FileNotFound

问题描述 投票:0回答:1

[我正在尝试使用Android Espresso测试设置代码覆盖率,并在Firebase测试实验室上运行测试。

测试是在Firebase上执行的,因此我认为一切都应该“正常”进行。但是,在Firebase测试实验室中生成的coverage.ec文件不包含任何覆盖率信息。

无论我尝试什么,我都看不到要它实际生成覆盖率信息。

[当查看@ Firebase测试实验室日志时,我看到此堆栈跟踪:

10-02 23:55:37.746: W/System.err(7917): java.io.FileNotFoundException: /jacoco.exec (Read-only file system)
10-02 23:55:37.746: W/System.err(7917):     at java.io.FileOutputStream.open0(Native Method)
10-02 23:55:37.746: W/System.err(7917):     at java.io.FileOutputStream.open(FileOutputStream.java:287)
10-02 23:55:37.746: W/System.err(7917):     at java.io.FileOutputStream.<init>(FileOutputStream.java:223)
10-02 23:55:37.746: W/System.err(7917):     at org.jacoco.agent.rt.internal_8ff85ea.output.FileOutput.openFile(FileOutput.java:67)
10-02 23:55:37.746: W/System.err(7917):     at org.jacoco.agent.rt.internal_8ff85ea.output.FileOutput.startup(FileOutput.java:49)
10-02 23:55:37.746: W/System.err(7917):     at org.jacoco.agent.rt.internal_8ff85ea.Agent.startup(Agent.java:122)
10-02 23:55:37.746: W/System.err(7917):     at org.jacoco.agent.rt.internal_8ff85ea.Agent.getInstance(Agent.java:50)
10-02 23:55:37.746: W/System.err(7917):     at org.jacoco.agent.rt.internal_8ff85ea.Offline.<clinit>(Offline.java:31)
10-02 23:55:37.746: W/System.err(7917):     at org.jacoco.agent.rt.internal_8ff85ea.Offline.getProbes(Offline.java:51)
10-02 23:55:37.746: W/System.err(7917):     at com.example.idea.MainActivity.$jacocoInit(Unknown Source:12)
10-02 23:55:37.746: W/System.err(7917):     at com.example.idea.MainActivity.<init>(Unknown Source:0)
10-02 23:55:37.746: W/System.err(7917):     at java.lang.Class.newInstance(Native Method)
10-02 23:55:37.746: W/System.err(7917):     at android.app.Instrumentation.newActivity(Instrumentation.java:1174)
10-02 23:55:37.746: W/System.err(7917):     at android.support.test.runner.MonitoringInstrumentation.newActivity(MonitoringInstrumentation.java:754)
10-02 23:55:37.746: W/System.err(7917):     at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2669)
10-02 23:55:37.746: W/System.err(7917):     at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2856)
10-02 23:55:37.746: W/System.err(7917):     at android.app.ActivityThread.-wrap11(Unknown Source:0)
10-02 23:55:37.747: W/System.err(7917):     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1589)
10-02 23:55:37.747: W/System.err(7917):     at android.os.Handler.dispatchMessage(Handler.java:106)
10-02 23:55:37.747: W/System.err(7917):     at android.os.Looper.loop(Looper.java:164)
10-02 23:55:37.747: W/System.err(7917):     at android.app.ActivityThread.main(ActivityThread.java:6494)
10-02 23:55:37.747: W/System.err(7917):     at java.lang.reflect.Method.invoke(Native Method)
10-02 23:55:37.747: W/System.err(7917):     at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438)
10-02 23:55:37.747: W/System.err(7917):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807)

看着其他几个具有类似错误的线程,我看到了一些建议:

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

到我已经完成的AndroidManifest.xml。

以及:

debug { testCoverageEnabled true }

在我的应用程序的build.gradle文件中。

您也可以在此处查看完整的jacoco配置:

apply plugin: 'jacoco'
jacoco {
    toolVersion = "0.8.4"
}
def coverageSourceDirs = [
        'src/main/java',
        'src/debug/java'
]

tasks.withType(Test) {
    jacoco.includeNoLocationClasses = true
    jacoco.destinationFile = file("$buildDir/jacoco/jacocoTest.exec")
}

task jacocoTestReport(type : JacocoReport, dependsOn : 'testDebugUnitTest') {
    group       = 'Reporting'
    description = 'Generate JaCoCo coverage reports'

    reports {
        xml.enabled  = true
        html.enabled = true
    }

    classDirectories = fileTree(
            dir      : 'build/intermediates/classes/debug',
            excludes : [
                    '**/R.class',
                    '**/R$*.class',
                    '**/*$ViewInjector*.*',
                    '**/*$ViewBinder*.*',
                    '**/BuildConfig.*',
                    '**/Manifest*.*',
                    '**/*RealmProxy.*',
                    '**/*ColumnInfo.*',
                    '**/*RealmModule*.*',
                    '**/AutoValue_*.*',
                    '**/Dagger*.*',
                    '**/*Module_Provide*Factory.*',
                    '**/*_Factory.*',
                    '**/*_MembersInjector.*',
                    '**/*_LifecycleAdapter.*'
            ]
    )

    sourceDirectories = files(coverageSourceDirs)
    executionData     = fileTree(
            dir     : "$buildDir",
            include : [ 'jacoco/testDebugUnitTest.exec', 'outputs/code-coverage/connected/*coverage.ec' ]
    )

    doFirst {
        files('build/intermediates/classes/debug').getFiles().each { file ->
            if (file.name.contains('$$')) {
                file.renameTo(file.path.replace('$$', '$'))
            }
        }
    }
}

task jacocoTestReportLocal(type : JacocoReport, dependsOn : ['testDebugUnitTest', 'createDebugCoverageReport']) {
    group       = 'Reporting'
    description = 'Generate JaCoCo coverage reports'

    reports {
        xml.enabled  = true
        html.enabled = true
    }

    classDirectories = fileTree(
            dir      : 'build/intermediates/classes/debug',
            excludes : [
                    '**/R.class',
                    '**/R$*.class',
                    '**/*$ViewInjector*.*',
                    '**/*$ViewBinder*.*',
                    '**/BuildConfig.*',
                    '**/Manifest*.*',
                    '**/*RealmProxy.*',
                    '**/*ColumnInfo.*',
                    '**/*RealmModule*.*',
                    '**/AutoValue_*.*',
                    '**/Dagger*.*',
                    '**/*Module_Provide*Factory.*',
                    '**/*_Factory.*',
                    '**/*_MembersInjector.*',
                    '**/*_LifecycleAdapter.*',
                    '**/models/**'
            ]
    )

    sourceDirectories = files(coverageSourceDirs)
    executionData     = fileTree(
            dir     : "$buildDir",
            include : [ 'jacoco/testDebugUnitTest.exec', 'outputs/code-coverage/connected/*coverage.ec' ]
    )

    doFirst {
        files('build/intermediates/classes/debug').getFiles().each { file ->
            if (file.name.contains('$$')) {
                file.renameTo(file.path.replace('$$', '$'))
            }
        }
    }
}

以及完整的应用程序build.gradle在这里:

apply plugin: 'com.android.application'
apply from: '../jacoco.gradle'

android {
    compileSdkVersion 28
    defaultConfig {
        applicationId "com.example.idea"
        minSdkVersion 22
        targetSdkVersion 28
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
        debug { testCoverageEnabled true }
    }
}

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation 'com.android.support:appcompat-v7:28.0.0'
    implementation 'com.android.support:support-media-compat:28.0.0'
    implementation 'com.android.support:support-v4:28.0.0'
    implementation 'com.android.support.constraint:constraint-layout:1.1.3'
    implementation 'com.google.firebase:firebase-analytics:15.0.0'
//    implementation 'com.google.firebase:firebase-core:15.0.0'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'com.android.support.test:runner:1.0.2'
    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
    androidTestImplementation 'com.android.support.test:rules:1.0.2'
}

apply plugin: 'com.google.gms.google-services'

以及此处的config.yml:

version: 2
references:

  ## Cache

  cache_key: &cache_key
    key: cache-{{ checksum "gradle/wrapper/gradle-wrapper.properties" }}-{{ checksum "build.gradle" }}-{{ checksum "app/build.gradle" }}
  restore_cache: &restore_cache
    restore_cache:
      <<: *cache_key
  save_cache: &save_cache
    save_cache:
      <<: *cache_key
      paths:
        - ~/.gradle
        - ~/.m2

  ## Workspace

  workspace: &workspace
               ~/workspace
  attach_debug_workspace: &attach_debug_workspace
    attach_workspace:
      at: *workspace
  attach_release_workspace: &attach_release_workspace
    attach_workspace:
      at: *workspace
  persist_debug_workspace: &persist_debug_workspace
    persist_to_workspace:
      root: *workspace
      paths:
        - app/build/outputs/androidTest-results
        - app/build/outputs/apk
        - app/build/outputs/code-coverage
        - app/build/test-results
  persist_release_workspace: &persist_release_workspace
    persist_to_workspace:
      root: *workspace
      paths:
        - app/build
  attach_firebase_workspace: &attach_firebase_workspace
    attach_workspace:
      at: *workspace
  persist_firebase_workspace: &persist_firebase_workspace
    persist_to_workspace:
      root: *workspace
      paths:
        - firebase

  ## Docker image configuration

  android_config: &android_config
    working_directory: *workspace
    docker:
      - image: circleci/android:api-28-alpha
    environment:
      TERM: dumb
      _JAVA_OPTIONS: "-Xmx2048m -XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap"
      GRADLE_OPTS: '-Dorg.gradle.jvmargs="-Xmx2048m"'
  gcloud_config: &gcloud_config
    working_directory: *workspace
    docker:
      - image: google/cloud-sdk:206.0.0
    environment:
      TERM: dumb

  # Google Services

  export_gservices_key: &export_gservices_key
    run:
      name: Export Google Services key environment variable
      command: echo 'export GOOGLE_SERVICES_KEY="$GOOGLE_SERVICES_KEY"' >> $BASH_ENV
  decode_gservices_key: &decode_gservices_key
    run:
      name: Decode Google Services key
      command: echo $GOOGLE_SERVICES_KEY | base64 -di > app/google-services.json

  # Google Cloud Service

  export_gcloud_key: &export_gcloud_key
    run:
      name: Export Google Cloud Service key environment variable
      command: echo 'export GCLOUD_SERVICE_KEY="$GCLOUD_SERVICE_KEY"' >> $BASH_ENV
  decode_gcloud_key: &decode_gcloud_key
    run:
      name: Decode Google Cloud credentials
      command: echo $GCLOUD_SERVICE_KEY | base64 -di > ${HOME}/client-secret.json

jobs:

  # Build debug APK for unit tests and an instrumented test APK

  build_debug:
    <<: *android_config
    steps:
      - checkout
      - *restore_cache
      - run:
          name: Download dependencies
          command: ./gradlew androidDependencies
      - *save_cache
      - *export_gservices_key
      - *decode_gservices_key
      - run:
          name: Gradle build (debug)
          command: ./gradlew -PciBuild=true :app:assembleDebug :app:assembleAndroidTest
      - *persist_debug_workspace
      - store_artifacts:
          path: app/build/outputs/apk/
          destination: /apk/

  # Build release APK

  build_release:
    <<: *android_config
    steps:
      - checkout
      - *restore_cache
      - run:
          name: Download dependencies
          command: ./gradlew androidDependencies
      - *save_cache
      - *export_gservices_key
      - *decode_gservices_key
      - run:
          name: Gradle build (release)
          command: ./gradlew -PciBuild=true :app:assembleRelease
      - *persist_release_workspace
      - store_artifacts:
          path: app/build/outputs/apk/
          destination: /apk/
      - store_artifacts:
          path: app/build/outputs/mapping/
          destination: /mapping/

  # Run unit tests

  test_unit:
    <<: *android_config
    steps:
      - checkout
      - *restore_cache
      - run:
          name: Download dependencies
          command: ./gradlew androidDependencies
      - *save_cache
      - *export_gservices_key
      - *decode_gservices_key
      - run:
          name: Run unit tests
          command: ./gradlew -PciBuild=true :app:testDebugUnitTest
      - *persist_debug_workspace
      - store_artifacts:
          path: app/build/reports/
          destination: /reports/
      - store_test_results:
          path: app/build/test-results/
          destination: /test-results/

  # Run instrumented tests

  test_instrumented:
    <<: *gcloud_config
    steps:
      - *attach_debug_workspace
      - *export_gcloud_key
      - *decode_gcloud_key
      - run:
          name: Set Google Cloud target project
          command: gcloud config set project i-de-a
      - run:
          name: Authenticate with Google Cloud
          command: gcloud auth activate-service-account [email protected] --key-file ${HOME}/client-secret.json
      - run:
          name: Echo sha1 variable for debugging
          command: echo ${CIRCLE_SHA1}
      - run:
          name: Run instrumented test on Firebase Test Lab
          command: gcloud firebase test android run --type instrumentation --app app/build/outputs/apk/debug/app-debug.apk --test app/build/outputs/apk/androidTest/debug/app-debug-androidTest.apk --device model=Nexus6P,version=27,locale=en_US,orientation=portrait --no-use-orchestrator --environment-variables coverage=true,coverageFile="/sdcard/coverage.ec" --directories-to-pull=/sdcard --timeout 20m --results-dir=${CIRCLE_SHA1}
      - run:
          name: Create directory to store test results
          command: mkdir firebase
      - run:
          name: Download instrumented test results from Firebase Test Lab
          command: gsutil -m cp -r -U gs://test-lab-hzda62mwyy730-n7hcz7bxtxrx0/${CIRCLE_SHA1} /root/workspace/firebase/
      - *persist_firebase_workspace
      - store_artifacts:
          path: firebase/
          destination: /firebase/

  # Submit JaCoCo coverage report

  report_coverage:
    <<: *android_config
    steps:
      - checkout
      - *restore_cache
      - run:
          name: Download dependencies
          command: ./gradlew androidDependencies
      - *attach_debug_workspace
      - *attach_firebase_workspace
      - run:
          name: Move Firebase coverage report
          command: mkdir -p app/build/outputs/code-coverage/connected && cp firebase/${CIRCLE_SHA1}/Nexus6P-27-en_US-portrait/artifacts/coverage.ec app/build/outputs/code-coverage/connected/coverage.ec
      - *export_gservices_key
      - *decode_gservices_key
      - run:
          name: Generate JaCoCo report
          command: ./gradlew -PciBuild=true :app:jacocoTestReport
      - run:
          name: Upload coverage report to CodeCov
          command: bash <(curl -s https://codecov.io/bash)
      - store_artifacts:
          path: app/build/reports/
          destination: /reports/

workflows:
  version: 2
  workflow:
    jobs:
      - build_debug
      - build_release
      - test_unit
      - test_instrumented:
          requires:
            - build_debug
      - report_coverage:
          requires:
            - build_release
            - test_unit
            - test_instrumented

https://github.com/kyleo83/idea

您可以在此GitHub上查看完整的代码。

这里的任何帮助将不胜感激!

android firebase jacoco firebase-test-lab
1个回答
0
投票

来自https://github.com/jacoco/jacoco/issues/968

该解决方案在jacoco中有据可查,但是对于Android用户来说,您需要在/src/androidTest/resources/jacoco-agent.properties中添加内容为output=none的文件,以便jacoco可以正常启动,并且覆盖范围将被正常写入并正确传输稍后由android gradle插件覆盖实现。

© www.soinside.com 2019 - 2024. All rights reserved.