In part one of the series, we discussed using JDeveloper 12c and Maven as a build tool. Users know that there are problems with this configuration. The first Maven integration was a real bumpy experience. In later 12c versions (12.2.1.x), the integration got better and better.

JDeveloper version 12.2.1.4 fixed most bugs. However, one thing broke with 12.2.1.4. You can’t run JUnit tests with Maven!

Part two of the series showed a workaround for this problem and how to implement it.

The final third part discusses some shortcomings of the workaround and how to implement it on large scale projects with multiple models.

Shortcomings

Firstly, we implemented the workaround presented in part two directly into the fixture generated by the ‘Build Junit Test Suite for Business Component’ wizard. Implementing the workaround in the fixture is a start. However, in real-world projects, there are multiple model projects which build a hierarchy. We don’t want to add the code for the workaround to every fixture. 

Secondly, we may have different environments using different DB connections. We need a way to choose the right DB connection for the environment we are running the tests on. Avoiding hard-coding values is mandatory.

Finally, debugging a test case inside JDeveloper is easy; doing this outside needs some preparation.

Multi-Model Projects

Implementing the code for the fixture’s workaround is feasible if you have one model project to test only. Why?

Everything is hard-coded in the workaround. The name of the DB server, user name, and password is hard-coded in the solution. When you have to test multiple model projects, you need to change this information for every fixture. The remaining part of the code is always the same. 

To make things reusable, we need a way to pass this information to the fixture somehow. If we use our own Java class, we can pass this information as parameters to a method. Or we use setters to define the values before creating the application module. 

The original, generated code uses the Configuration class to call the method ‘createRootApplicationModule(…)’ with two parameters in the fixture constructor. We can create a Java class providing the same method. 

To prepare the workaround for these different environments, we need to pass the DB server’s address to use the calling program’s credentials. 

Maven uses a pom.xml file to configure the build process. We define the information as part of the pom.xml. Our particular configuration class reads the information to connect the application module to the right DB.

The maven-sure-fire plugin executes the Junit tests. We configure the plugin for each project that needs to run JUnit tests.

We pass the needed information as command line parameters to the sure-fire plugin. In the class, we can read the parameters and set them.

String jdbcurl =    System.getProperty("de.hahn.blog.maven.test.jdbcUrl");
String jdbcuser = System.getProperty("de.hahn.blog.maven.test.jdbcUser");
String jdbcpwd = System.getProperty("de.hahn.blog.maven.test.jdbcPwd");

Different Environments

A developer works typically on his machine only. Coding and testing on the same device using one DB server is OK. However, in more significant projects, it is normal to have different environments (development, test, pre-production, and production). Each environment defines a stage in the development process. The environments use different DB servers with other credentials.  

In the last paragraph, we configured each test project to pass the needed information. Now, the problem is that the environment dictates the parameters and not just the project. Maven comes to rescue here too. Maven uses profiles to define different settings. A profile holds the parameters with their values for one environment. Profiles are defined in the settings.xml file you find in your .m2 folder. The build process can select which profile to activate for each run (or stage or environment). Still, we need to pass the parameters to the maven-surefire-plugin. 

We define the parameters in the profile into the global environment and read them from there when calling the maven-surefire-plugin:

<profiles>
 <!-- Profil for local VM -->
    <profile>
      <id>environmentLocalVM</id>
      <properties>
... 
        <env.de.hahn.maven.jdbc.user>hr</env.de.hahn.maven.jdbc.user>
<env.de.hahn.maven.jdbc.pwd>hr</env.de.hahn.maven.jdbc.pwd>
<env.de.hahn.maven.jdbc.url>jdbc:oracle:thin:@\/\/localhost:1521\/XEPDB1</env.de.hahn.maven.jdbc.url>
...
      </properties>
    </profile>
</profiles>

Then we change the ‘argLine’ property of the maven-surefire-plugin in the pom.xml of each test project to read the parameters from the env location like

-Dde.hahn.maven.test.jdbcUser=${env.de.hahn.maven.jdbc.user} 
-Dde.hahn.maven.test.jdbcPwd=${env.de.hahn.maven.jdbc.pwd} 
-Dde.hahn.maven.test.jdbcUrl=${env.de.hahh.maven.jdbc.url}

We can have multiple profiles that we use according to the environment. Using profiles allows us to overwrite the parameters easily from the calling program. It can be a CI tool or a shell script or maven directly.

Debugging external JUnit Tests

Sometimes a test case errors out, and you need to debug the test case to get hold of the problem. Debugging a test case is an easy task when you run the test case inside JDeveloper. Doing so outside JDeveloper, when the surefire maven plugin executes the test cases. In this case, you need to use a remote debugger to connect to the running test case. 

Configure global Maven for Debug

Firstly we need to tell the surefire maven plugin that we want to debug the test cases by defining a parameter in the global maven settings (Tools-Preferences-Maven-Settings):

-Dmaven.surefire.debug 

Running the test goal from the maven pom.xml will now tell you that it waits for a remote debug session to connect:

Once we see this message, we can start a remote debug session inside JDeveloper.

Setting up a Remote Debug Session in Jdeveloper

To simplify this, we create a new ‘Run Configuration’:

Here we select the ‘Remote Debugging’ checkbox and use the ‘Remote’ node to configure the connection:

Finally, we select the new ‘Run Configuration’

and get the connect dialog:

Here we can change the parameters and store them in the ‘run configuration’. Once the debug session is connected to the java process, we can debug the test cases inside JDeveloper.

Setting breakpoints or looking up the current data works as if you debug a process inside JDeveloper:

You can download the sample application from GitHub. It was created using JDeveloper 12.2.1.4 and uses the HR DB schema.

Timo Hahn