2

Upgrading to JUnit5, we faced a limitation:

@Test(expected = NullPointerException.class)

is no longer possible. We should use org.junit.jupiter.api.Assertions.assertThrows these days. Normally, it takes a lambda, and it works if we set

android.compileOptions {
    sourceCompatibility JavaVersion.VERSION_1_8
    targetCompatibility JavaVersion.VERSION_1_8
}

The problem is that we'd prefer to stay at Java 7 for the release build (it would require huge amount of testing to prove that all ancient devices that we still strive to support, work correctly with Java 8).

Is there a clean way to set sourceCompatibility for unit test only in Android Studio?

Alex Cohn
  • 56,089
  • 9
  • 113
  • 307
  • 1
    JUnit5 targets Java8. Use JUni4 and `ExpectedException` rule. – M. Prokhorov Nov 28 '17 at 15:49
  • Maybe I’m not getting it, but… a *release build* should create a release version of the application rather than a build of the unit tests, shouldn’t it? Are you deploying unit tests to the end users? – Holger Nov 28 '17 at 16:06
  • @Holger: no, tests are internal. But I don't know how to set `sourceCompatibility` for specific build configuration - in this case, for unit tests. – Alex Cohn Nov 28 '17 at 16:55
  • Hmm, I don’t know anything about you build system, but shouldn’t it be two entirely different projects, with a clear *unit tests→application code* dependency? There should be no problem compiling a project with Java 8 target (the unit tests) with a dependency to another project/library compiled with Java 7 target (the application). For unit tests, it’s not even necessary to be build by the same tool (android studio) than the application code, you only have to compile the application source to just classes, rather than bundling them in the deployment format. – Holger Nov 28 '17 at 17:17
  • @Holger yes, there should be no problem conceptually. The question is - how this can be beautifully expressed in the Android Studio. Thanks for your input, I have updated the question. – Alex Cohn Nov 28 '17 at 18:07
  • @Holger, note that AS runs Unit tests with host JRE (on your PC), while the restrictions or concerns about Java 8 are only relevant for the code deployed to device. – Alex Cohn Nov 28 '17 at 18:10
  • That's how I expected it. So, does Android Studio have a notion of projects like Eclipse? – Holger Nov 28 '17 at 21:04
  • @Holger Android Studio is modded IntelliJ. The same plugins can be used. So, it can do everything that IntelliJ can do. – Alex Cohn Nov 28 '17 at 21:17

1 Answers1

1

TL;NR: The following code works for gradle tasks, but the IDE does not understand that the app classes don't use Java 8.

In Android Studio 3.0.1 with gradle plugin version 3.0.1, the following works:

tasks.all {
  task ->
    if (task.name.endsWith('UnitTestJavaWithJavac')) {
      android.compileOptions.setSourceCompatibility(JavaVersion.VERSION_1_8)
      android.compileOptions.setTargetCompatibility(JavaVersion.VERSION_1_8)
    }
  }
}

Now I can write

@Test
public void throwNPE() {
  assertThrows(NullPointerException.class, () ->
    { int [] nullarr = null; nullarr.clone(); }
  );
}

and still keep my app code at Java 7 or even Java 6.

To check how Java compiler was actually configured, I can run javap on my app classes and on my test classes:

javap -cp build/intermediates/classes/debug -verbose com.example.Main | grep major
javap -cp build/intermediates/classes/test/debug -verbose com.example.Tests | grep major

The results are:

major version: 51
major version: 52

Unfortunately, the IDE does not understand that the app classes don't use Java 8, and warns in the following situation (see this undocumented example of Java 8 incompatibility with Java 7):

interface I {}

public class Main implements I {

  <T extends I> T getI() { return (T) this };
  void foo(I value) {
    System.out.println("foo(I)");
  }
  void foo(String value) {
    System.out.println("foo(String)");
  }
  void warn() {
    foo(getI());
  }
}

Android Studio warning

In spite of this warning, 'Make Proect' and 'Run Test' both pass.

Alex Cohn
  • 56,089
  • 9
  • 113
  • 307