Integrating with JUnit

While writing classes with main methods can get the job done with unit testing, we can do better. You typically write tests in Java using a framework such as JUnit. JUnit is a complete testing framework with handy life cycle hooks and annotations that you can use to write tests easily. Let's look at converting our test module to use JUnit.

Here are the steps:

  1. Get the JUnit jars. You can either download them from the JUnit website (http://junit.org/junit4/) or download them from Maven Central. It also has a dependency on the hamcrest core JAR file, so download that too. Place the JARs in a lib folder. We intend to add this location to the module path. The downloaded JAR files are available in the lib folder at 12-build-tools-and-testing/02-testing/src/packt.sortutil.test.
  2. Use the JUnit annotations in your test code. Here's the new SortUtilTest written as a JUnit test:
        public class SortUtilTest { 
          private SortUtil sortUtil; 
          @Before public void setUp() { 
            sortUtil = new SortUtil(); 
          } 
          @Test     
          public void testReturnsSameSize() { 
            List out = sortUtil.sortList(Arrays.asList("b", "a", "c")); 
            SortUtil sortUtil = new SortUtil(); 
            assert out.size() == 3; 
          } 
          @Test   
          public void sortsList() { 
            List out = sortUtil.sortList(Arrays.asList("b", "a", "c")); 
            assert "a".equals(out.get(0)); 
            assert "b".equals(out.get(1)); 
            assert "c".equals(out.get(2)); 
          } 
        } 
  1. Specify that the test module has a dependency on the JUnit library. Since the JUnit JAR will be added to the classpath, it will be treated as an automatic module. So, to establish dependency, you'll need to figure out what the automatic module name will be from the JAR file name. The JAR file downloaded is called junit-4.12.jar. Stripping off the .jar extension and the version number, we'll end up with the automatic module--name - junit.
  2. Declare the test module as  open. The way JUnit works is by scanning the annotations on your classes to figure out what to do. So, it needs access to the test classes in your test module. You can either export the necessary packages or declare them as open. I prefer the latter, since we only need to enable reflective access to JUnit.

Here's the updated module definition of the packt.sortutil.test module:

          open module packt.sortutil.test { 
            requires packt.sortutil; 
            requires junit; 
          } 

Let's compile and run the test to see what the behavior is:

$ javac -d out --module-source-path src --module-path lib --module 
packt.sortutil,packt.sortutil.test

The only change this time is the addition of the lib directory as the module path. This lets the Java platform treat the JUnit JAR as an automatic module, which is what we need. This should succeed without any errors.

What happens if we run this now? We are running the JUnit test runner class, so that's what we need to specify in the core JUnit runner class JUnitCore (in the automatic module junit) as value to the --module argument to Java. Following that is the fully qualified name of the class under test--SortUtilTest. Here's what the command looks like:

$ java --module-path out:lib --module junit/org.junit.runner.JUnitCore
packt.util.test.SortUtilTest

Will it work? It will not! Here's the error you should see:

JUnit version 4.12.E 
Time: 0.001 
There was 1 failure: 
1) initializationError(org.junit.runner.JUnitCommandLineParseResult) 
java.lang.IllegalArgumentException: Could not find class [packt.util.test.SortUtilTest] 

Turns out Java is unable to find the SortUtilTest class. Why is that? The compiled module is available in the out directory that we've passed to the --module-path option! There's a reason why it does not see the class.

Think back to the module resolution discussion in Chapter 8, Understanding Linking and Using jlink. The module resolution is a traversal of dependent modules originating from the starting point--the module you specify in the --module argument. Since the starting point here is the JUnit automatic module, the module resolution process never resolves the application or test modules. This is because the JUnit automatic module does not read our modules! The way to solve this problem and have the runtime see our modules is using the --add-modules option. Passing our test module using this option should result in the execution completing successfully:

$ java --module-path out:lib --add-modules packt.sortutil.test --module junit/org.junit.runner.JUnitCore packt.util.test.SortUtilTest 
JUnit version 4.12 
.. 
Time: 0.005 
 
OK (2 tests) 

Note that we did not have to add the packt.sortutil module to the --add-modules option. Just the test module sufficed. This is because the test module has an explicit dependency on packt.sortutil through the requires declaration, and so the module resolution process now picks it up automatically!

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.188.61.81