Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Android Studio 3.0 #256

Closed
timrijckaert opened this issue Sep 7, 2017 · 22 comments
Closed

Android Studio 3.0 #256

timrijckaert opened this issue Sep 7, 2017 · 22 comments

Comments

@timrijckaert
Copy link

Hiya,

I'm a bit confused how the setup of Spek for Android projects should be.
Previously in Android Studio 2.3.3 everything seemed to be working just fine with the Spek plugin installed.

Following the documentation I retried from scratch in a clean new project since I can't share my particular project.
The problem seems to exist there as well.

Upon running I get:

WARNING: TestEngine with ID 'spek' failed to discover tests org.junit.platform.commons.util.PreconditionViolationException: Could not load class with name: vrt.be.rijckaert.tim.spekproblem.CalculatorSpec

I also tried to add a compileDebugUnitTestSources Gradle task before running the unit tests.

You can find the full example here
How can I get Spek to run with Android Studio 3.0.0 ?
To my understanding something goes wrong with the new bundled JUnit 5 runner?

Thanks in advance

Tim

@raniejade
Copy link
Member

Can you try using JUnit Platform 1.0.0-RC2?

@timrijckaert
Copy link
Author

timrijckaert commented Sep 8, 2017

Problem persists.
Although tests now seem to run in CLI not but still not in Android Studio 3.0.0-beta4.

showing CLI successfully running tests with 1 failing test like expected

I tried out different run configs.

First
Spek config with Spek IDEA plugin

Showing the run configuration screen from Android Studio with a Spek Run config for the subject under test

outputs stacktrace like above.
WARNING: TestEngine with ID 'spek' failed to discover tests org.junit.platform.commons.util.PreconditionViolationException: Could not load class with name: vrt.be.rijckaert.tim.spekproblem.CalculatorSpec

Second:
JUnit Run Config

java.lang.ClassNotFoundException: com.intellij.junit5.JUnit5IdeaTestRunner

Showing the run configuration screen from Android Studio with a Android JUnit 4 Run config for the subject under test

I pushed everything to the repository.

@heliofvj
Copy link

heliofvj commented Sep 10, 2017

JUnit 5 supports gradle for java projects. Gradle for Android projects has some differences that break compatibility.
junit-team/junit5#204

Even if you are using a java module in your project, Android Studio uses an IntelliJ build that depends on APIs of an outdated JUnit 5 Milestone. Your tests will fail when executed from Android Studio directly.
Using JUnit M6 should solve this problem, in theory. In reality, the error persists. This time because kotlin classes won't be properly recognized. Tests written in java classes using JUnit 5 work with no problems.

If you intend to use only Android modules in your project, the android-junit plugin by @aurae solves all the problems above. The github project has a sample showing how your project can be configured to run JUnit 5 based tests.
https://github.com/aurae/android-junit5

@timrijckaert
Copy link
Author

Hmm thanks for this.
However this does not seem to work for me like it should.
I updated the repository to reflect implementing this library.
PR's are very much welcome to better understand what it is I'm doing wrong.

I now get a nice output in my CLI

screen shot 2017-09-12 at 14 52 52

However still unable to get this to run in Android Studio 3.0.0-beta5.

WARNING: Ignoring test class using JUnitPlatform runner: vrt.be.rijckaert.tim.spekproblem.CalculatorSpec
Exception in thread "main" java.lang.NoSuchMethodError: org.junit.platform.launcher.Launcher.execute(Lorg/junit/platform/launcher/LauncherDiscoveryRequest;)V
	at com.intellij.junit5.JUnit5IdeaTestRunner.startRunnerWithArgs(JUnit5IdeaTestRunner.java:61)
	at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:51)
	at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
	at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at com.intellij.rt.execution.application.AppMainV2.main(AppMainV2.java:131)

Process finished with exit code 1
Empty test suite.

Would be nice to see a complete sample with Kotlin + Spek + AndroidJUnit5 support repo that actually runs in Android Studio 3.0.0

Thanks

Tim Rijckaert

@raniejade
Copy link
Member

Can you try using 1.0.0-RC2 on you're repo you are still using RC1?

@raniejade
Copy link
Member

Can you check your dependencies? Let me know if you're pulling in JUnit Platform 1.0.0. Haven't tested that release yet and it may introduced some breaking changes to the API.

@mannodermaus
Copy link

Also, if you're using android-junit5 with Android Studio, please make sure to add the embedded runtime for JUnit 5 as another compile-only dependency to your build script. You can check my readme for more details on this, but basically AS didn't keep up with the changing API of the JUnit milestone releases, and is still stuck with an older (and now, incompatible) bundled version.

@timrijckaert
Copy link
Author

timrijckaert commented Sep 13, 2017

I have updated the JUnit Platform dependency to 1.0.0 still no success.
@aurae I think I already added the dependency.

@paulinabls
Copy link

@timrijckaert https://github.com/paulinabls/hangman here you can find a working config for AS 3.0 Preview and Spek v 1.1.2 . I couldn't make it work with Spek v 1.1.4. See app module in given repo for android kotlin project. Module sumbodule contains tests that can be run with Spek plugin.

@mannodermaus
Copy link

mannodermaus commented Sep 14, 2017

@timrijckaert Interesting that adding the runtime doesn't seem to be working for you. In the android-junit5 example project, I can fix or break unit test execution in AS 3.0 just by commenting out the testCompileOnly dependency on android-junit5-embedded-runtime. You could also try and experiment with other configurations to apply that dependency in, maybe just go full rogue and specify it as testApi? Otherwise not sure why this would be happening.

@mannodermaus
Copy link

I've found another thing that might be causing your issue, and it's related to how the artifact was published to jcenter. Can you try pulling in the android-junit5 dependencies directly from my Bintray by putting the following repository above your jcenter() in the build script:

maven { url "https://dl.bintray.com/aurae/maven" }

If that's actually the fix, I'll prepare a hotfix for jcenter.

@timrijckaert
Copy link
Author

Does not seem to do anything.
It would be just nice if somebody could share a working setup of this.
Just the simplest Android project.

@raniejade
Copy link
Member

Very sorry, haven't look at this any further yet. My local android dev environment is broken and I haven't find time yet to fix it.

@raniejade
Copy link
Member

@timrijckaert can you add this to app/build.gradle?

afterEvaluate {
    compileDebugUnitTestKotlin {
        finalizedBy copyKotlinDebugUnitTestClasses
    }

    compileDebugKotlin {
        finalizedBy copyKotlinDebugClasses
    }
}

task copyKotlinDebugUnitTestClasses(type: Copy) {
    from "build/tmp/kotlin-classes/debugUnitTest"
    into "build/intermediates/classes/test/debug"
}

task copyKotlinDebugClasses(type: Copy) {
    from "build/tmp/kotlin-classes/debug"
    into "build/intermediates/classes/debug"
}

Apparently android and kotlin has their own output directory, when running from AS compiled kotlin and android outputs are not consolidated hence the ClassNotFoundException. Tested it with Gradle 4.2 and Android Studio 3.0 Beta 6.

@raniejade
Copy link
Member

Let's see if AS 3.0 Beta 7 fixes this https://issuetracker.google.com/issues/64804587.

@timrijckaert
Copy link
Author

I had already added this albeit in another form.

afterEvaluate {
    android.buildTypes.all {
        def name = it.name

        def copyTask = project.task(type: Copy, "copyKotlin${name.capitalize()}UnitTestClasses") {
            from "build/tmp/kotlin-classes/${name}UnitTest"
            into "build/intermediates/classes/test/$name"
        }

        project.tasks.getByName("compile${name.capitalize()}UnitTestSources").finalizedBy copyTask
    }
}

Could you setup a test Android project with a simple Spek test that is able to run in AS 3.0 Beta 6-7?
Maybe also check in the run configs?
It would be really helpful to compare the setups

@raniejade
Copy link
Member

build.gradle

// Top-level build file where you can add configuration options common to all sub-projects/modules.

buildscript {
    ext.kotlin_version = '1.1.50'
    repositories {
        google()
        jcenter()
        maven { url "http://dl.bintray.com/jetbrains/spek" }
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:3.0.0-beta6'
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
        classpath "de.mannodermaus.gradle.plugins:android-junit5:1.0.0"
        classpath 'org.junit.platform:junit-platform-gradle-plugin:1.0.0'

        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    }
}

allprojects {

    repositories {
        google()
        jcenter()
    }
}

app/build.gradle

apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'

apply plugin: "de.mannodermaus.android-junit5"

android {
    compileSdkVersion 26
    buildToolsVersion "26.0.1"
    defaultConfig {
        applicationId "com.tvcoursework.kotlinintrocourse"
        minSdkVersion 26
        targetSdkVersion 26
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }

    sourceSets {
        main.java.srcDirs += 'src/main/kotlin'
        test.java.srcDirs += 'src/test/kotlin'
    }
}

junitPlatform {
    filters {
        engines {
            include 'spek'
        }
    }
}

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation 'com.android.support:appcompat-v7:26.1.0'
    implementation 'com.android.support.constraint:constraint-layout:1.0.2'
    implementation 'com.android.support:design:26.1.0'
    testImplementation 'junit:junit:4.12'

    testImplementation "org.jetbrains.kotlin:kotlin-test:$kotlin_version"
    testImplementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"

    testImplementation('org.jetbrains.spek:spek-api:1.1.5') {
        exclude group: 'org.jetbrains.kotlin'
    }
    testImplementation('org.jetbrains.spek:spek-junit-platform-engine:1.1.5') {
        exclude group: 'org.junit.platform'
        exclude group: 'org.jetbrains.kotlin'
    }

    testImplementation "org.junit.platform:junit-platform-runner:1.0.0"

    androidTestImplementation('com.android.support.test.espresso:espresso-core:3.0.1', {
        exclude group: 'com.android.support', module: 'support-annotations'
    })
    implementation"org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version"
}

afterEvaluate {
    compileDebugUnitTestKotlin {
        finalizedBy copyKotlinDebugUnitTestClasses
    }

    compileDebugKotlin {
        finalizedBy copyKotlinDebugClasses
    }
}

task copyKotlinDebugUnitTestClasses(type: Copy) {
    from "build/tmp/kotlin-classes/debugUnitTest"
    into "build/intermediates/classes/test/debug"
}

task copyKotlinDebugClasses(type: Copy) {
    from "build/tmp/kotlin-classes/debug"
    into "build/intermediates/classes/debug"
}

@timrijckaert
Copy link
Author

Yes!
Finally.

Thanks for these.
I pushed the changes to my Repo and it now works like intended both in Android Studio 3.0-6 as well as in the CLI.

@mannodermaus
Copy link

mannodermaus commented Sep 27, 2017

(Copied from #271 for future reference by anybody who might stumble upon this)

The proposed task declarations will only copy over classes in the debug build type, leaving release and any other potential build type out of the picture. Also, the dependency section could use some clean-up (e.g. you don't need the junit-platform-runner unless you want to run JUnit 4 in the first place, and the code doesn't apply the dependencies from the android-junit5 plugin altogether):

build.gradle:

buildscript {
    ext.kotlin_version = "1.1.50"
    ext.spek_version = "1.1.5"

    dependencies {
        // 1. Add the android-junit5 Gradle plugin as a classpath dependency
        classpath "de.mannodermaus.gradle.plugins:android-junit5:1.0.0"
    }
}

<module>/build.gradle:

// 2. Apply the android-junit5 plugin alongside your app's plugins
apply plugin: "de.mannodermaus.android-junit5"

android {
    // 3. Extend the Java source set with the Kotlin folders
    sourceSets {
        main.java.srcDirs += "src/main/kotlin"
        test.java.srcDirs += "src/test/kotlin"
    }
}

// 4. Configure spek's TestEngine to be detected by JUnit 5
junitPlatform {
    filters {
        engines {
            include "spek"
        }
    }
}

dependencies {
    // 5. Add the dependencies on spek & its required co-dependencies to the test scope
    testImplementation("org.jetbrains.spek:spek-api:$spek_version") {
        exclude group: "org.jetbrains.kotlin"
    }
    testImplementation("org.jetbrains.spek:spek-junit-platform-engine:$spek_version") {
        exclude group: "org.junit.platform"
        exclude group: "org.jetbrains.kotlin"
    }
    testImplementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"

    // 6. Add the dependencies on JUnit 5 & the embedded runtime for AS to the test scope
    testImplementation junit5()
    testCompileOnly "de.mannodermaus.gradle.plugins:android-junit5-embedded-runtime:1.0.0-RC3-rev1"
}

// 7. Finally, configure AS to copy over Kotlin classes for each build type to where the IDE can pick them up
afterEvaluate {
    android.buildTypes.each {
        def name = it.name

        def copyTestTask = project.task(type: Copy, "copyKotlin${name.capitalize()}UnitTestClasses") {
            from "build/tmp/kotlin-classes/${name}UnitTest"
            into "build/intermediates/classes/test/$name"
        }
        project.tasks.getByName("compile${name.capitalize()}UnitTestKotlin").finalizedBy copyTestTask

        def copyMainTask = project.task(type: Copy, "copyKotlin${name.capitalize()}Classes") {
            from "build/tmp/kotlin-classes/${name}"
            into "build/intermediates/classes/$name"
        }
        project.tasks.getByName("compile${name.capitalize()}Kotlin").finalizedBy copyMainTask
    }
}

@curiousily
Copy link

Can you build & run your apk when 7. is added? I receive the following gradle error

> Task with name 'compileReleaseUnitTestSources' not found in project ':app'.

Using AS 3.0 Beta 7

@timrijckaert
Copy link
Author

timrijckaert commented Oct 5, 2017

Nope indeed it is broken again. :'(
For now I have just fixed it with putting an if check before the task.

afterEvaluate {
    android.buildTypes.each {
        def name = it.name

        def copyTestTask = project.task(type: Copy, "copyKotlin${name.capitalize()}UnitTestClasses") {
            from "build/tmp/kotlin-classes/${name}UnitTest"
            into "build/intermediates/classes/test/$name"
        }

        if (project.tasks.findByName("compile${name.capitalize()}UnitTestKotlin") != null) {
            project.tasks.getByName("compile${name.capitalize()}UnitTestKotlin").finalizedBy copyTestTask
        }

        def copyMainTask = project.task(type: Copy, "copyKotlin${name.capitalize()}Classes") {
            from "build/tmp/kotlin-classes/${name}"
            into "build/intermediates/classes/$name"
        }

        if (project.tasks.findByName("compile${name.capitalize()}Kotlin") != null) {
            project.tasks.getByName("compile${name.capitalize()}Kotlin").finalizedBy copyMainTask
        }
    }
}

@osipxd
Copy link

osipxd commented Nov 9, 2017

With this I get DexException on assemble.
I've removed these tasks from compileDebugKotlin and problem disappears:

afterEvaluate {
    compileDebugUnitTestKotlin {
        finalizedBy copyKotlinDebugUnitTestClasses
        finalizedBy copyKotlinDebugClasses
    }
}

task copyKotlinDebugUnitTestClasses(type: Copy) {
    from "build/tmp/kotlin-classes/debugUnitTest"
    into "build/intermediates/classes/test/debug"
}

task copyKotlinDebugClasses(type: Copy) {
    from "build/tmp/kotlin-classes/debug"
    into "build/intermediates/classes/debug"
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

7 participants