Thursday, June 4, 2009

Unit testing your Intellij Idea plugin in a CI build

It's relatively easy to write a unit test for your Intellij Idea plugins that would work from under Idea.
Just extend an IdeaTestCase or LightIdeaTestCase, add some Mockito and enjoy :-)

The challenge is to set this up for an Ant build run on a continuous integration server like Bamboo - you just don't get the Idea set up on every potential elastic build agent that may turn out to run your build ;-)
I wanted my build to be self-contained - no external dependencies on stuff that may or may not be there, everything gets nicely checked out from the svn.

I came up with the following configuration:

Set up new Idea home



My lib contains an idea_version folder reflecting the structure of the actual Idea installation:

  • lib folder containing all the jars from Idea's lib dir - definitely all are not required, but it seemed to be too much work to actually find out which ones are,
  • bin folder that is necessary for the test framework to start - namely it should contain:

    • idea.properties - just copied as is, this is the marker that Idea uses to determine the folder is it's home,
    • log4j.dtd - also copied as is,
    • log.xml - modified so that the 'headless' Idea can find the log4j.dtd file:
      <!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">

      You may use an unmodified one, but then you need to make sure that the log4j.dtd file is in the current working directory of the test runner.


Set up test runner



I use this test target:
<property name="idea.home" location="${basedir}/lib/idea_9833"/>

<target name="idea7.test" depends="idea7.test.build, idea7.testproject">
<mkdir dir="${output}/test/xml-report"/>
<mkdir dir="${output}/test/system/log"/>
<junit dir="${output}/test" fork="true" forkmode="once" printsummary="on">
<jvmarg line="${jvm.args}"/>
<jvmarg value="-Xbootclasspath/a:${idea.home}/lib/boot.jar"/>
<jvmarg value="-Xmx256M"/>
<jvmarg value="-ea"/>
<jvmarg value="-Xdebug"/>
<!--<jvmarg value="-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=5006"/>-->
<sysproperty key="java.awt.headless" value="true"/>
<sysproperty key="java.compiler" value="NONE"/>
<sysproperty key="idea.config.path" value="${output}/test/config"/>
<sysproperty key="idea.system.path" value="${output}/test/system"/>
<sysproperty key="idea.load.plugins" value="false"/>
<classpath>
<path path="${java.class.path}"/>
<path refid="testpath"/>
<fileset dir="${idea.home}/lib" includes="*.jar"/>
<pathelement path="${output}/test/classes"/>
<pathelement path="${idea.home}/bin"/>
</classpath>
<batchtest todir="${output}/test/xml-report">
<fileset dir="${basedir}/test" includes="${test.includes}"
excludes="${test.excludes}"/>
<formatter type="xml"/>
<formatter type="plain"/>
</batchtest>
</junit>
</target>


Some highlights:
  • Make sure both Idea lib and bin are on the classpath.
  • Make sure you have Java on the classpath - for some reason I had not.
  • Notice the -Xbootclasspath jvmarg - <bootclasspath> hasn't worked for me.
  • Remote debugger may be handy sometimes.

0 comments:

Post a Comment