Skip to content

Bug Fix for “Contributing to Eclipse”

It has been a long time since my last post. I was very busy. Sorry for that.

Here comes another technical article on a book: “Contributing to Eclipse: Principles, Patterns, and Plug-Ins”, published by Addison-Wesley. It is written by Erich Gamma (co-author of the “OO-Bible” Design Patterns, technical director of the IBM Research lab Zurich and developer of the Eclipse Platform) and Kent Beck (creator of Extreme Programming).

contributing_eclipse_2.jpg contributing_eclipse_3.gif contributing_eclipse_1.jpg

The book is obviously on how to extend the Eclipse platform with your own “contributions”, aka Plug-Ins. The book is very interesting as it comes from two authors who “come from the inside” of Eclipse. Thus they reveal all kinds of background information that a normal author could easily have missed.

However the book was written in 2003 and builds on a previous Eclipse release, prior version 3.0. When reading through the examples in the book, I eventually got to chapter 7, where Erich and Kent are developing the JUnit Plug-In. I think the one nowadays shipped with the standard Eclipse distribution.

There, page 62, they say: “For now, we can’t imagine how your understanding of Eclipse would be helped by seeing the details of starting a new virtual machine and communicating with it via sockets. See Appendix A for the details.”

Here they talk about how to properly run your test cases. That is “outside” the Eclipse JVM instance. To easily get above that bump, I downloaded their source code from here. In this archive, there are two classes that are senseless for the reader to implement himself, that is TestRunner and SocketTestRunner. So I imported them into my own Eclipse Project (Note: Circle_1!).

First I changed the obvious stuff, like in TestRunner.java, line 77 and 130:

JUnitPlugin plugin = JUnitPlugin.getPlugin();

to match my slightly different class names:

MyJUnitPlugin plugin = MyJUnitPlugin.getPlugin();

However, when I started my Plug-In Project (“run as Eclipse Application”) and selected an object type in a dummy project (“ADemoProject”) and then tried to start my own JUnit implementation (“Run MyTest”), nothing happened.

The Eclipse View “Error Log” gave the hint that there was a NullPointerException in TestRunner, line 78:

java.lang.NullPointerException
at org.eclipse.core.runtime.Plugin.getDescriptor(Plugin.java:268)
at org.theyellowmarker.gamma.TestRunner.computeClasspath(TestRunner.java:78)

But then looking at my Eclipse source of TestRunner, the deprecation warnings gave me the hint to do a bit of research, have a look at the screenshot below:

contributing_eclipse_4.jpg

Obviously, plugin.getDescriptor() was the reason for the NullPointerException. Used to the standard Java JDK philosophy, where deprecated methods usually still do their job somehow, it took my a bit of Eclipse API reading to figure out how to recode the whole section. Again, see the screenshot below:

contributing_eclipse_5.jpg

To get the plug-in path for our plug-in, we have to get “the Bundle” from the static method of

org.eclipse.core.runtime.Platform:

// has to be unique id of activation plugin.
Bundle bundle = Platform.getBundle("org.theyellowmarker.MyJUnit");

Note that the string “org.theyellowmarker.MyJUnit” is the unique id of my plug-in in the MANIFEST.MF file. You have to change it according to your setup. The url of the project is then found by the subsequent lines:

URL url = FileLocator.find(bundle, new Path("/"), null);
classPath[0] = FileLocator.toFileURL(new URL(url, "bin")).getFile();
classPath[1] = FileLocator.toFileURL(new URL(url, "junit.jar")).getFile();

Note: I am not sure about the last line here. Could be useless.

Next, also replace the deprecated SocketUtil.findUnusedLocalPort on line 61 with:

port = SocketUtil.findFreePort();

Last, the SocketTestRunner class is given to the external JVM by name, so you have to change the first line of the class, where MAIN_CLASS is defined, to match your own package structure:

static final String MAIN_CLASS = "org.eclipse.contribution.junit.SocketTestRunner";

to:

static final String MAIN_CLASS = "org.theyellowmarker.gamma.SocketTestRunner";

Now everything works again, as expected. You can download my plug-project here: myjunit.zip

and the dummy project containing the test cases here: ademoproject.zip

Make sure, when running the plug-in “in action” (that is in the second Eclipse workbench) to right click on the ASillyClassTest symbol with the green class dot on its left, otherwise, you don’t get the “Run My Test” menu entry in the context menu:

contributing_eclipse_6.jpg

On test will fail, one will succeed. The console output on the first Eclipse workbench should be something like this:

2 test[s] started...
Test org.theyellowmarker.test.ASillyClassTest->testDemoTrue() started.
Test org.theyellowmarker.test.ASillyClassTest->testDemoFalse() started.
Test org.theyellowmarker.test.ASillyClassTest->testDemoFalse() failed.
junit.framework.AssertionFailedError: null
at junit.framework.Assert.fail(Assert.java:47)
at junit.framework.Assert.assertTrue(Assert.java:20)
at junit.framework.Assert.assertFalse(Assert.java:34)
at junit.framework.Assert.assertFalse(Assert.java:41)
at org.theyellowmarker.test.ASillyClassTest.testDemoFalse(ASillyClassTest.java:27)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at junit.framework.TestCase.runTest(TestCase.java:168)
at junit.framework.TestCase.runBare(TestCase.java:134)
at junit.framework.TestResult$1.protect(TestResult.java:110)
at junit.framework.TestResult.runProtected(TestResult.java:128)
at junit.framework.TestResult.run(TestResult.java:113)
at junit.framework.TestCase.run(TestCase.java:124)
at junit.framework.TestSuite.runTest(TestSuite.java:232)
at junit.framework.TestSuite.run(TestSuite.java:227)
at junit.framework.TestSuite.runTest(TestSuite.java:232)
at junit.framework.TestSuite.run(TestSuite.java:227)
at org.theyellowmarker.gamma.SocketTestRunner.runTests(SocketTestRunner.java:39)
at org.theyellowmarker.gamma.SocketTestRunner.main(SocketTestRunner.java:26)

All tests finished

As I move forward in the Book, I will publish eventual updates on this topic.

P.S: Here is the full set of files after “Circle 1″: first-circle.zip

Be Sociable, Share!

2 Comments

  1. Monika Krug wrote:

    Great! Just what I need to complete my thesis! I have read about half of the book and my Eclipse plugin is almost finished, now I was struggling with running JUnit tests programmatically and thinking how I could avoid having to a) type all those pages of code for the TestRunner and SocketTestRunner b) adjust them for Eclipse 3.2.

    You may have to add the note about the CPL licence to your files, though.

    Thursday, June 14, 2007 at 11:10 | Permalink
  2. Stuart Blair wrote:

    Thanks. As the tedium of copying TestRunner.java code from a page took me back to the evenings of the early 80s spent entering games from listings in a Vic20 magazine, it occurred to me that I was actually living in the post-Google era. One quick search for the class I was hammering in et voila. Your page. Thank you for removing the necessity for another coffee!

    Monday, May 5, 2008 at 17:49 | Permalink

Post a Comment

Your email is never published nor shared.