Skip to main content

Testing your Java code in XPages (part 1)

This topic will lead to a series of articles. It depends how deep I will get, but I will try to stay as much general as possible and avoid solutions that work just in my current case.

It's all inspired by nice hack that Maks Zhuk showed in his blogpost http://mzhuk.blogspot.com/2014/02/unit-tests-for-lotus-domino-applications.html . Since I want to automate everything, I'll take it step further with Gradle.

XPages run on top of a OSGi runtime and so they use system of features and plugins. This can lead to some dependency troubles when you just want to do plain Java work. Christian Guedemann showed how to make this work nicely with Maven http://guedebyte.wordpress.com/2014/04/07/automated-build-with-jenkins-some-progress/ . Sadly Gradle can't read p2 update sites, which can Maven do using Tycho plugin. Even when you try to Mavenize it in some standard way like using eclipse:to-maven, I couldn't use it afterwards since some plugins contain jars as libs in them (probably all plugins that are not stored as jar, but as a folder in notes installation) and this resulted in nested jars.

So if you want to get really serious about building and testing your code with provided XPages runtime classes, you might be better of with Maven (or please let me know how to for Gradle to use it). I my case I just want to test my code and as theory of testing says, I should minimize dependency on other code using mocking or similar approaches. In that case I won't be probably calling XPages code at all, so I just need it to compile my code.

In Notes world it is really hard to separate yourself from Notes API, because big part of logic usually depends on view lookups etc. You could of course create own layer that hides this, but then you are probably just increasing complexity, cost and all other bad aspects of your code and it'd be probably better to switch to different platform that doesn't provide such nice and powerful infrastructure.

Testing your code from separate project

Maks's article showed that when you change nature of your on disk project to Java, you can use it as classic Java project afterwards. Which means that Eclipse will compile it when needed and you can use it as project dependency.

I won't repeat his article here. But in case his blog goes offline, the trick is in adding
  <buildCommand>
    <name>org.eclipse.jdt.core.javabuilder</name>
    <arguments>
    </arguments>
  </buildCommand>
</buildSpec>
<natures>
  <nature>org.eclipse.jdt.core.javanature</nature>
</natures>

into .project file of the on disk project.

Good thing about this is that Eclipse knows about all other dependencies, including plugins, so you don't have problems described above.

One small warning. If you run your tests and change your code from a link stack trace, you are changing it in your on disk project. So you have to synchronize it with the nsf to get it there. And you know what happens if you change code on both sides, ... .

If you have your on disk project configured this way, you can easily create another Java project in your workspace that has this project as dependency.  And then you can do any testing you want, but since we are in Notes environment, we might have few problems that you have to address and I'll get to them later. Some problems are:
  • Initialization of NotesThread - test are running under seperate JVM, so you have to act as in standalone Java program
  • You no longer have current database - again, test are running as standalone Java program
  • You can't rely on XPages infrastructure, because there is none when you run your tests (you should test your code, not your app on domino)
It's really hard to define straight line between unit testing and integration tests in Notes environment, but if you can get to real unit testing level, so with no dependency on external code, you are fine. Otherwise you have to work your way through the issues and even might be better of running your tests on Domino and drive them using selenium (or create some framework to run them directly, which should be feasible).

Example application

I'll continue to use same sample application from previous posts that is hosted at https://bitbucket.org/pradnik/gradledominosample . For this demo I'll move my simple computation from XPage to a Java class. At first it'll have no dependency on Notes or XPages classes, to keep it simple.

Then I'll create new project in same repository to use it for tests.

Adding Java to XPages

I'll describe it quickly, because you probably know how to do it if you are reading this :). I like to follow approaches that Jesse Gallagher uses in his XPages Scaffolding . So I have a class called SimpleController that does simple computation:



 I can use it from a XPage for example in this way:

 and

 But I want to test my class directly, not using XPages. Adding it to the XPage on other hand will test it using my Selenium test from previous post too.

Creating Java project for your tests

Create plain Java project and put it in same Git repository. I use layout of source code that is used by Gradle so I had to reconfigure source folder to /src/test/java.

Then add your on-disk-project as dependency

Remember add odp version (that you've modified to show as Java project), not the version with .nsf at the end. That's actual nsf version that uses Eclipse virtual filesystem and your test classes wouldn't see your code.

Then you need to add library that you use for your tests. In my case I have bundle of TestNG, Mockito and Powermock (that I had to use to get arround some issues noted above). But for this example TestNG would be enough (or JUnit if you preffer).  I've also installed TestNG plugin into my Domino Designer.

My test class looks like:

OK, it's just for demonstration and I probably could test more even in such simple case, but it's for a different debate.

Since I have TestNG plugin in my Domino Designer, I can right click on that class and run it as a TestNG Test and I get:








If I break my Java class and multiply for example by 3 (remember, if you change it in nsf, you have to sync with odp), I get an exception (this time from TestNG view, but same is in console too):




Never trust a test that you haven't seen to fail :)

But wait, I was talking about Gradle not Eclipse. So let's switch gears.

 Building Java in XPages with Gradle

We want to automate all of this proces, so at first we have to teach Gradle to build our Java file.  We already have a build.gradle file in on-disk-project, but it doesn't tell Gradle that we have some Java in the project too. We have to enable it using:
 apply plugin: 'java'
and then tell Gradle where to look for sources
sourceSets {
    main {
        java {
            srcDir 'Code/Java'
        }
    }
}
That's all.

Building test project with Gradle

In our test project we have to tell Gradle that we need TestNG and we work with our XPages app. I used standard project layout, so it know where to look for source code of my test classes. Complete build.gradle is:
apply plugin:'java'

repositories {
    mavenCentral()
}

dependencies {
    testCompile group: 'org.testng', name: 'testng', version: '6.+'
    testCompile project(':xpagesApp')
}

test.useTestNG()
test.outputs.upToDateWhen { false }

I also added testJava  in settings.gradle in root of Git repository.

It's that simple because my code currently doesn't depend on Notes or XPages classes. Also it downloads all required libraries from Maven repository.

Running test

You can now run your tests from console using for example gradlew :testsJava:test
Z:\git\Testing\SampleDomino>gradle :testsJava:test
:testsJava:compileJava UP-TO-DATE
:testsJava:processResources UP-TO-DATE
:testsJava:classes UP-TO-DATE
:xpagesApp:compileJava
:xpagesApp:processResources UP-TO-DATE
:xpagesApp:classes
:xpagesApp:jar
:testsJava:compileTestJava
:testsJava:processTestResources UP-TO-DATE
:testsJava:testClasses
:testsJava:test

BUILD SUCCESSFUL
 If you run it with same command as in previous post gradle buildToServer test , it does all steps. It builds nsf from odp, pushes it to your server, runs your local Java tests and runs Selenium tests on that nsf. All with this one line.

Conclusion

With this infrastructure you can easily split your code in multiple projects and make them talk to each other. One of my biggest reasons is to keep NSF project clean, with no test code or resources. In such case you should also watch what you commit back to your repository and what gets synced back to nsf. Many files are created for tests and you may carry some garbage that you don't want.

In next part(s) I'll focus on issues that we have when calling Notes API and XPages classes.

Comments

Popular posts from this blog

Microsoft Word black box in numbering issue

This is awkward post, primarily to save the solution for future me. I have seen many people mentioning this problem over years and as I've struggled with it several times, I needed to find final and permanent solution.


All editions of Microsoft Word from time to time suffer from bug in numbering. Instead of a number, black box is displayed. Sometimes it happens right after document is opened, sometimes during editing. Probably some internal structure of document gets corrupted, so based on level of corruption, different fixes could help. Many of them are listed at https://answers.microsoft.com/en-us/office/forum/office_2010-word/ms-word-header-styles-are-showing-black-boxes/c427b21c-dcda-46ce-a506-b9a16c9f2f3f


I took different approach. Since docx is just standard zip package with xml files, I decided to try if I can fix it manually. And it worked.

When I extracted the docx, there was file called numbering.xml in word folder. When I examined that file, I found strange section in h…

Using JAX-RS inside NSF

Last week Christian Güdemann published new release of SmartNSF on OpenNTF that contains cool new feature that Christian tweeted before. With new CUSTOM strategy it allows direct execution
of Java code from REST API defined in router configuration. It's even better than it sounds as it initializes facesContext and XPages application if needed, so even access to beans works.

I needed to start to build new REST APIs for few databases, so I decided to test new SmartNSF option and also other available options for REST APIs on Domino (there are several, check references at the end for more info). Since CUSTOM strategy requires dependency on SmatNSF in NSF project and also implementation of CustomRestHandler interface, it'd force me to do more changes in my code that I wanted to. If I need to change my code, why not adjust it for JAX-RS spec anyway.

Existing Domino JAX-RS options had to packaged as plugins, which make it hard to call code that is currently in NSF. I could make it wor…

WSL, HCL Volt and some Docker

My list of new technologies to try was growing fast in past months, but now I finally can try to catch up with all the cool improvements that can be used to enhance my/your dev experience.
Microsoft has enhanced the Windows Subsystem for Linux this year and Docker completely changed the way Docker Desktop for Windows is integrated into the operating system. The most important change for me was that I can finally run Docker Desktop and VMWare Workstation on my machine in parallel. When I was looking for some good use cases to try how it works, HCL Domino was a logical choice. HCL started to even publish official Docker images for every release and some pre-releases are only available as Docker images. I have many test Domino machines running in VMs, but I had no HCL Volt. If you don't know that HCL Volt is - it's a new low-code platform that brings HCL Form Builder experience, now know as HCL Leap, to HCL Domino, which then serves as a data store and application server. When I…