mannodermaus / android-junit5

Testing with JUnit 5 for Android.
Apache License 2.0
859 stars 52 forks source link

Support per-test log display for JUnit 5 instrumentation tests #312

Closed workmichsem closed 4 months ago

workmichsem commented 8 months ago

I trying to use your library, and I can't see the test logs

There is my gradle:

plugins {
    id 'com.android.application'
    id 'org.jetbrains.kotlin.android'
    id 'org.jetbrains.kotlin.plugin.lombok' version '1.9.22'
    id 'io.freefair.lombok' version '8.1.0'
}
android {
    namespace 'com.example.myapplication'
    compileSdk 34
    defaultConfig {
        applicationId "com.example.myapplication"
        minSdk 29
        targetSdk 34
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
        testInstrumentationRunnerArguments["runnerBuilder"] = "de.mannodermaus.junit5.AndroidJUnit5Builder"
        testInstrumentationRunnerArguments["configurationParameters"] = "junit.jupiter.execution.parallel.enabled=true,junit.jupiter.execution.parallel.mode.default=concurrent"
        vectorDrawables {
            useSupportLibrary true
        }
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
    kotlinOptions {
        jvmTarget = '1.8'
    }
    buildFeatures {
        compose true
    }
    composeOptions {
        kotlinCompilerExtensionVersion '1.5.1'
    }
    packaging {
        resources {
            excludes += '/META-INF/{AL2.0,LGPL2.1}'
        }
    }
    testOptions {
        unitTests.all {
            useJUnitPlatform()
            animationsDisabled = true
        }
    }
    packagingOptions{
        exclude("META-INF/LICENSE.md")
        exclude("META-INF/LICENSE-notice.md")
        exclude("META-INF/DEPENDENCIES")
    }
}
kotlinLombok {
    lombokConfigurationFile file("lombok.config")
}
dependencies {
    implementation fileTree(include: ['*.jar'], dir: 'libs')
    implementation 'androidx.core:core-ktx:1.12.0'
    implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.6.2'
    implementation 'androidx.activity:activity-compose:1.7.0'
    implementation platform('androidx.compose:compose-bom:2023.08.00')
    implementation 'androidx.compose.ui:ui'
    implementation 'androidx.compose.ui:ui-graphics'
    implementation 'androidx.compose.ui:ui-tooling-preview'
    implementation 'androidx.compose.material3:material3'
    androidTestImplementation platform('androidx.compose:compose-bom:2023.08.00')
    androidTestImplementation 'androidx.compose.ui:ui-test-junit4'
    debugImplementation 'androidx.compose.ui:ui-tooling'
    debugImplementation 'androidx.compose.ui:ui-test-manifest'
    implementation 'junit:junit:4.13.2'
    implementation 'androidx.test.ext:junit-ktx:1.1.5'
    implementation 'androidx.test.ext:junit:1.1.5'
    implementation 'androidx.test:core-ktx:1.5.0'
    implementation 'androidx.test:rules:1.5.0'
    implementation 'androidx.test:runner:1.5.0'
    androidTestImplementation 'de.mannodermaus.junit5:android-test-core:1.4.0'
    androidTestImplementation 'de.mannodermaus.junit5:android-test-runner:1.4.0'
    androidTestImplementation 'de.mannodermaus.junit5:android-test-extensions:1.4.0'
    androidTestImplementation 'org.junit.jupiter:junit-jupiter-api:5.10.0'
    androidTestImplementation 'org.junit.jupiter:junit-jupiter:5.10.0'
} 

There is my simple code:

object AppConfigHolder {
    private var holder: HashMap<String, String> = HashMap()
    @Synchronized
    fun get(key: String): String? {
        return holder.getValue(key)
    }
    @Synchronized
    fun set(key: String, value: String) {
        holder.put(key, value)
    }
}

import org.junit.jupiter.api.extension.AfterEachCallback
import org.junit.jupiter.api.extension.BeforeEachCallback
import org.junit.jupiter.api.extension.ExtensionContext

class SetDefaultDataExtension : BeforeEachCallback, AfterEachCallback {

    override fun beforeEach(p0: ExtensionContext?) {
        println("---beforeEach")
        AppConfigHolder.set("222", "333")
    }

    override fun afterEach(p0: ExtensionContext?) {
        println("---afterEach")
    }
}

import org.junit.jupiter.api.Test
import org.junit.jupiter.api.extension.ExtendWith
import org.junit.jupiter.api.parallel.Execution
import org.junit.jupiter.api.parallel.ExecutionMode

@ExtendWith(SetDefaultDataExtension::class)
@Execution(ExecutionMode.CONCURRENT)
class MyTest  {
    @Test
    fun testSomething() {
        AppConfigHolder.get("222")
        println("---------TEST")
    }
}

The test passes, but all I see is "No logcat output for this device."

workmichsem commented 8 months ago

I found the answer. The fact is that when using JUnit 4, console output is usually available in the Logs tab. This is very convenient since the logs relate to only one selected test. But when using JUnit 5 Android Studio stops displaying them there. but still displays in Logcat

mannodermaus commented 7 months ago

Hey, thanks for reporting. The lack of easy access to per-test logs via the Test window in AS is something that has bugged me for a while as well. I haven't had the time to investigate how exactly it's able to pick up JUnit 4-based logs for this window, but it might be worth looking into the sources to figure out the integration here. My initial guess is that it is probably integrated via UTP, something that I remember looking into for a different issue a while back.

I'm renaming this ticket to track this as a feature request for the future. In the meantime, please refer to Logcat as a workaround!

mannodermaus commented 7 months ago

Huh, actually, after testing it again just now, there is some test output in AS for the JUnit 5 test. I wonder if this is resolved in a recent AS version? For context, I'm using Jellyfish Canary 7 and the output for your example code has the expected logs in the corresponding window. Could you share your AS version for reference?

Screenshot 2024-02-04 at 15 22 58

For a different angle, I am also noticing that while you are using the android-test libraries, there is no usage of the android-junit5 plugin. Instead, JUnit 5 is configured manually (e.g. via useJUnitPlatform in your testOptions). I don't recall anything specific to logs, but the plugin and instrumentation libraries do communicate with each other in several ways and the plugin configures the androidTest libraries in a certain way. Hence, it's possible that some of the plugin's work is missing in your project and causing the logs to not show. 🤔

bddckr commented 4 months ago

I'm running Android Studio Jellyfish | 2023.3.1 together with de.mannodermaus.android-junit5:1.10.0.0 and can confirm that the log output is visible per test in instrumentation tests!