speaking at the NY Java Sig and including remote attendees

This week, I spoke at the NY Java Sig reprising my QCon Java 10/11 Release Train talk.It was fun.  Last time I spoke at the NY Java Sig, I was the unplanned “opening act” for the main talk. This time, there were two planned speakers and I was one of them. I went second.

The NY Java Sig was hosted by Credit Suisse. They had 12 remote attendees from their Raleigh, NC office. We were able to hear, but not see them. They were able to see me.

I work on a distributed team so dealing with remote people I can or can’t see is just a part of me. I didn’t realize how much so until this presentation though.

When I present, I try to involve the audience a bunch of times. They raise their hands, vote on stuff, etc. Almost every time I did that, I asked someone in Raleigh to comment on how the vote looked there.

I got feedback at from the NY Credit Suisse representative that this was the first time that a speaker included them. (To be fair, most speakers don’t involve the NY audience either.) The really cool part is that I didn’t even realize I was doing it. It was just part of me; they were attending so I asked.

For this particular presentation, I had offered a couple “free conference level training” available to any of our offices remotely. So I had practiced with people I couldn’t see as well.

var in java 10

In my Java 10/11 talk, I ask the audience if this code compiles:

var var = "var";

I usually get about a 50/50 response. The answer is that it does compile due to backward compatibility. You could have a local variable named var and it should still work. When I gave the talk at the NY Java Sig tonight, Mark asked “what if you have a class named lower case var”. After wincing a bit at the lower case class name, I said I didn’t know. But I definitely wanted to find out.

The answer is actually pretty interesting – it depends on what version of Java you compile with!

Compiling var.java

Fierst I created a class


public class var {

  public static final String STR = "a";

}

This class compiles in Java 9 and below. It does not compile in Java 10 or 11. Instead you get the message:

as of release 10, 'var' is a restricted local variable type and cannot be used for type declarations

This means that you have to change the class name. However, you can still have a var.class file compiled in Java 9 or below.

Referencing that var.class file

Compiling OR running the code with Java 10/11 doesn’t let you refer to that var.class file either.

TripleVar.java:5: error: illegal reference to restricted type 'var'

Conclusion

If you followed bad practices and named your class var.class, you must change it. Even if you compiled in Java 9, it will not run in Java 10.

ant and junit 5

Ant now supports JUnit 5. The CodeRanch software uses Ant (because internet connections vary around the world). This blog post describes how I upgraded.

What isn’t supported

While doing this, I learned that not everything supported in JUnit 4 for Ant is currently supported with JUnit5. In particular:

Preparing my environment

Updating Jars for Ant

Ant’s JUnitLauncher page gives a list of the required jars. I decided to download them directly from a Maven repository rather than using the copies in my local repository so I have the latest ones. I grabbed the jars needed for both JUnit 4 and 5 so I could test transitioning.

  • junit-platform-commons.jar
  • junit-platform-engine.jar
  • junit-platform-launcher.jar
  • opentest4j.jar
  • junit-vintage-engine.jar
  • junit-jupiter-api.jar
  • junit-jupiter-engine.jar
  • junit-jupiter-params.jar (I do a lot of junit parameterized testing)
  • apiguardian-api (dependency for junit parameterized testing)
  • junit.jar (use legacy junit jar for migration)
  • hamcrest-all.jar (not sure why needed now and not before)

I copied all these jars to the lib directory of my Ant install. If you forgot to do this before the next step, update the Eclipse preferences again now. Otherwise, you will get this message when running a build.

java.lang.NoClassDefFoundError: org/junit/platform/launcher/core/LauncherFactory

Switch Eclipse to the JUnit 5 runner but run JUnit 4 tests

This is easy.

  • Updated Eclipse preferences to point to it (Ant > Runtime – Ant Home)
  • Add the JUnit 5 library to your project’s classpath
  • Run > Run Configurations
  • Select the launch config for your test runner(s)
  • Change the test runner pull down to select JUnit 5
  • Observe the tests still pass

Switch Ant to the JUnit 5 runner but run JUnit 4 tests

Unlike Eclipse, this is not easy.

Updated Ant file

    • removed JaCoco wrapper for JUnit Ant task (was using this to give Sonar the test coverage – need to investigate the replacement)
    • removed code for setting custom system property – replaced with code described in setting System Property blog post
    • replaced the <junit> tags with <junitlauncher> tags
    • removed the attributes that are not supported by the new tag: showoutput=”no” fork=”yes” forkmode=”once”
    • changed printsummary attribute value from “yes” to “true”
    • replace batchtest tag with testclasses tag and change attribute to outputdir
    • switch formatter tag to listener tag using new attributes
    • added to nested classpath in junitlauncher task <pathelement location=”${junit.jars.dir}”/>
    • changed fileset to use .class instead of .java in matching
    • removed code to pass in all existing system properties. (since JUnit being run in the same VM, this is no longer necessary)
      <!-- Pass along all the system properties to the junit task -->
      <syspropertyset>
        <propertyref builtin="all"/>
        </syspropertyset>
      

Actually migrating the code to JUnit 5

While JUnit 5 can run JUnit 5 tests, I decided to migrate them all.

  1. Migrate core assertions/imports
    1. Ran the program I wrote to migrate most of the pieces.

Migrating the unit tests

  1. Created launch configurations to replace old runners
    1. Removed “all test runner”. Can do this in modern IDEs without the old Classpath Suite
    2. Right clicked Eclipse project and choose run as junit test. Saved this as my new JUnit 5 launch config favorite so can run all tests in one click.
    3. Repeated right clicking /src/test/java (we have separate folders for unit and integration tests) to create a launch config for only unit tests). I should change this to the Maven naming convention of IT
  2. Migrated Mockito code (we had about 50 affected classes in JForum)
    1. In Eclipse project, did search for @RunWith(MockitoJUnitRunner.class) and @RunWith(MockitoJUnitRunner.Silent.class)
    2. Right click in search view > Replace All
    3. Replace with: @ExtendWith(MockitoExtension.class)
    4. Right click project > Source > Organize imports
  3. Migrated parameterized tests by hand (we only had 1)
  4. Migrated the one test with a timeout by hand
  5. Removed a custom assertArrayEquals() method we had written (presumably before JUnit had it). The migration program changed the order of parameters in the method call, but not the custom method so it didn’t compile.
  6. Changed one assertThat manually. It was using a matcher in an odd way.
  7. Now that the code compiles, ran the unit tests. 43/2416 failed.
  8. We were missing a setup call to load a property file in a commonly used superclass. (This appeared to work before due to a different order of test runs). Fixing that one test brought it to 19 failures.
  9. The remembered I forgot to migrated tests that used (expected=MyException.class) to use the new assertions – found these by searching for FIXME). That was the rest.
  10. Finally, I had two tests that relied on special encoding which the converter program broke. I rolled back these parts manually.

Migrating the integration tests

  1. We add a JUnit Runner for all our functional test. It loaded an in memory database (or real database depending on your configuration). I migrated this to an extension. The code is a lot clearer as an extension which is nice.
  2. Then I search/replaced @RunWith(JavaRanchFunctionalTestRunner.class) with @ExtendWith(CodeRanchFunctionalTestExtension.class) and did an organized imports on the folder for the functional tests.

Removing JUnit 4

After migrating, I removed JUnit 4 and the vintage engine from:

  • Eclipse project classpath
  • Jar file in project
  • Ant install’s lib directory