Alex Cohn
Alex Cohn

Reputation: 57173

Junit5 in Android Studio: assertThrows and Java 8

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?

Upvotes: 2

Views: 667

Answers (1)

Alex Cohn
Alex Cohn

Reputation: 57173

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.

Upvotes: 1

Related Questions