Download the JMock library
The latest stable release of JMock is 2.4.0 and can be downloaded here, or in a unix shell with
- wget http://www.jmock.org/dist/jmock-2.4.0-jars.zip
I am not particularly fond of the way the source and binaries are packed together in some of these libraries. My preference would be to isolate the functional code from the IDE resources (IDE usage appears to be the motivation for the current packaging scheme).
I also like to have the JMock javadocs on hand and we can download them here or in a shell
- wget http://www.jmock.org/dist/jmock-2.4.0-javadoc.zip
Decide How to Package the Library
I have seen various ways to package 3rd-party libraries in Eclipse plug-ins, and the final word on packaging a library generally comes from the owner. Until jmock.org provides an Eclipse distribution, whatever method we choose will be fine, but it is in no way the authoritative means of distribution.
Embedded as a Jar in a plug-in with custom code
While this might be fine for very small projects, I would caution against it. There is always a chance that the library owner will create a standard Eclipse plug-in someday, or that someone else will produce an Eclipse plug-in for a functionally equivalent (or better) library, so it is a good idea to keep our code separate from their code.
Unwrapped binary or source plug-in
Unless we were planning to modify code in the 3rd-party library (in which case we would be forking the distribution and assuming responsibility for the modified code) there is really no need to unpack the archive. Why should our automated build process spend cycles re-compiling unchanging library source code or re-packing standard binaries? I am confident that library jars inside plug-ins incur little to no performance penalty over plug-in jars with unwrapped binaries (unfortunately, I do not recall where I originally read that and would like to provide a cited reference).
Plug-in containing multiple jars
This will probably satisfy our requirements. Since the JMock libraries and their dependencies are distributed as a single unit, I feel comfortable putting them all inside a single plug-in and exposing only the top-level org.jmock packages (along with org.hamcrest packages as needed). The PDE provides a good way to manage dependencies among version-ranges of libraries. Because JMock is already provided as a distribution with a single, downloadable file that contains specifically-versioned dependencies, that management is already handled for us (it just happens that the version range is restricted to a single value per library).
Plug-in per jar
This would be ideal, but, as consumers of the libraries and not as the actual distributors, it should not be up to us to manage declaration of the interdependencies of the libraries and the fine-grained packaging and versioning of these plug-ins for Eclipse. Individual plug-ins probably would not benefit us much over the multi-jar plug-in approach, especially if we plan to upgrade the JMock distribution as new versions become available, and this approach may even add unwanted maintainance costs for re-packaging the libraries into 8 plug-ins, as opposed to 1 plug-in, every few months.
Create a new Eclipse Plug-in Project
Now that we have decided to package the JMock distribution as a single plug-in, the creation of the plug-in project itself is very straightforward with the New Project Wizard.
New -> Project... -> Plug-in Development -> Plug-in From existing JAR archives
Select all the JMock JARs that were unzipped from the downloaded archive. If you had originally put these JARs inside a plug-in with your test code and are now moving them into their own plug-in, then you can Add... the JARs from your Workspace. Since we have the JARs stored in some other location on the filesystem, we will Add External....
The final word on the naming and versioning of a plug-in, much as the physical packaging, comes from the owner of the library. If we were planning to modify the JMock source code, then we would probably use the same naming convention that we use for our other plug-in projects, for example we would call our fork of JMock my.company.jmock. Since we are planning to consume JMock as-is, then we will want to give the plug-in a more conventional name, such as org.jmock. Similarly, since we will not modify the libraries, we can follow the current jmock versioning scheme and say that the plug-in has a version of 2.4.0.
By default, the Wizard checks the Unzip the JAR archives into the project option; here we want to uncheck that option.
By default, the Wizard will automatically export all available Java packages for the plug-in. My preference is to export only those packages that I will access from my test code. To get started, the list includes org.jmock, org.jmock.api and org.jmock.integration.junit4. As we write more tests, we might need some custom matchers that are available in org.hamcrest.Matchers but are not exposed by JMock.
Get JUnit 4.4
Unfortunately, just as with Spring 2.5 JUnit support, JMock has a dependency on JUnit 4.4, but JUnit 4.3 is bundled with Eclipse. If we were to try to use the JMock.class runner in a JUnit 4 test case, we would see the following compilation error:
- The type org.junit.internal.runners.JUnit4ClassRunner cannot be resolved. It is indirectly referenced from required .class files
Since JMock depends on JUnit 4.4, and since we are bundling JMock and its dependencies as a single plug-in, should the JUnit 4.4 jar be included in the same plug-in even though it is not part of the downloadable distribution on jmock.org? I do not know an absolute right answer.
We can get the JUnit 4.4 jar from here or download it from a unix shell with
- wget http://downloads.sourceforge.net/junit/junit-4.4.jar?modtime=1184865382&big_mirror=0
Once the junit4.4.jar is in the workspace, we can add it to the plug-in's classpath in the MANIFEST.MF.
Write a JMock Test Case
The JMock Cookbook is a great resource for getting started with JMock. Our goal is to get a single test-case running with a mock object to verify our plug-in configuration.
We can declare our dependency on org.jmock in our test plug-in's MANIFEST.MF. We want to ensure that org.jmock is declared as a dependency before org.junit4.
I have seen the following initialization error from the JMock test runner if org.junit4 is declared first (presumably because JMock is using JUnit 4.4 and Eclipse is using 4.3)
We can create a new test case that uses a Mock Object and the JMock test runner. The following code should be enough:
package my.test.plugin;
import java.util.concurrent.Callable;
import java.util.concurrent.Executors;
import org.jmock.Mockery;
import org.jmock.integration.junit4.JMock;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(JMock.class)
public class SomeTest {
private final Mockery mockery = new Mockery();
@Test
public void testSomething() throws Exception {
final Callable<?> callable = mockery.mock(Callable.class);
Executors.newSingleThreadExecutor().submit(callable).get();
}
}
We should now see a legitimate test failure! We expect that the Executor will call Callable#get, and from the JMock failure trace, that is exactly what happened.
Now let's emend our test code so that the mock object expects an invokation of Callable#call.
package my.test.plugin;
import org.jmock.Expectations;
....
@Test
public void testSomething() throws Exception {
final Callable<?> callable = mockery.mock(Callable.class);
mockery.checking(new Expectations() {
{
one(callable).call();
}
});
Executors.newSingleThreadExecutor().submit(callable).get();
}
}
We have a green bar!
It appears that we have successfully incorporated the JMock 3rd-party libraries into a re-usable Eclipse plug-in.
2 comments:
Hi. I have a couple of questions...
What does your jMock eclipse plugin do?
Why use a plugin instead of putting the JAR into a lib/ directory in your project?
Great questions:
I currently use this jMock plug-in as a dependency of my own Eclipse plug-in test fragments. Whenever I write a new Eclipse plug-in, say tims.eclipse.plugin, I create a parallel test fragment (in this case tims.eclipse.plugin.tests). The fragment adds an additional dependency on the org.jmock plug-in in order to use the classes in any package exported by the jMock plug-in.
Centralizing the jMock plug-in in a single location allows all of my test fragments to reference that single plug-in, instead of each fragment embedding the jar in its own lib directory. Also, if jMock eventually releases an official plug-in, then I will be able to replace mine with the official version with very little pain. In addition, as the jMock library changes over time, using a plug-in will make upgrading and version-management much easier than having jars spread across test fragments. For these types of reasons, it is generally bad form to embed a third-party jar directly in a plug-in.
Post a Comment