Saturday, August 23, 2008

Eclipse Test Oriented Templates

Eclipse templates decrease some of the drudgery of re-typing common patterns. While there are quite a few posts that describe the process for importing, exporting and writing custom templates, I have not encountered too many custom templates geared specifically to the test-oriented community (aside from the standard Test and test Java type member templates). With the recent addition of the Templates View in Ganymede, the abilty to paste snippets from the clipboard to this view, and a new feature that allows the automatic addition of Java imports, I will keep the idea of factoring common code patterns to templates in the back of my mind during my day-to-day coding. Because I am a test-oriented developer, I have found the following particularly useful:

JUnit templates:


setup (Context Java type members) Used to create a JUnit4 setUp method

${:import(org.junit.Before)}
@Before
public void setUp() {
}


setup_before_class (Context Java type members) Used to create a static JUnit4 Class setUp method

${:import(org.junit.BeforeClass)}
@BeforeClass
public static void setUpBeforeClass() {
}


teardown (Context Java type members) Used to create a JUnit4 tearDown method

${:import(org.junit.After)}
@After
public void tearDown() {
}


teardown_after_class (Context Java type members) Used to create a static JUnit4 Class tearDowan method

${:import(org.junit.AfterClass)}
@AfterClass
public static void tearDownAfterClass() {
}


Test_expected_exception (Context Java type members) Used to create a JUnit4 test method that expects an Exception to be thrown

@${testType:newType(org.junit.Test)}(expected = ${cursor})
public void ${testname}() throws Exception {
${staticImport:importStatic('org.junit.Assert.*')}
}


Test_timeout (Context Java type members) Used to create a JUnit4 test method with a time limit

@${testType:newType(org.junit.Test)}(timeout = ${cursor})
public void ${testname}() throws Exception {
${staticImport:importStatic('org.junit.Assert.*')}
}


JMock templates:



run_with_jmock (Context Java) Used to annotate a Test Class that it should be run with the JMock runner

${:import(org.junit.runner.RunWith,org.jmock.integration.junit4.JMock)}
@RunWith(JMock.class)


mockery_for_classes (Context Java type members) Used to create a new JMock mockery for Classes

${:import(org.jmock.Mockery,org.jmock.lib.legacy.ClassImposteriser)}
private final Mockery mockery = new Mockery() {
{
setImposteriser(ClassImposteriser.INSTANCE);
}
};


mockery_for_interfaces (Context Java type members) Used to create a new JMock mockery for Interfaces

${:import(org.jmock.Mockery)}
private final Mockery mockery = new Mockery();


checking (Context Java statements) Used to setup JMock expectations

${:import(org.jmock.Expectations)}

mockery.checking(new Expectations() {
{
}
});


General templates:


sysdebug (Context Java statements) Slightly more robust than sysout, labels the value printed to standard out.

System.out.println("${word_selection}=["+${word_selection}${}+"].");${cursor}


templates.xml


You can also copy the following text to a templates.xml file and import it through Eclipse Window -> Preferences -> Java -> Editor -> Templates


<?xml version="1.0" encoding="UTF-8"?><templates><template autoinsert="true" context="java-statements" deleted="false" description="Setup JMock expectations" enabled="true" name="checking">${:import(org.jmock.Expectations)}&#13;
mockery.checking(new Expectations() {&#13;
{&#13;
}&#13;
});</template><template autoinsert="true" context="java-members" deleted="false" description="Create a new JMock Mockery" enabled="true" name="mockery_for_classes">${:import(org.jmock.Mockery,org.jmock.lib.legacy.ClassImposteriser)}&#13;
private final Mockery mockery = new Mockery() {&#13;
{&#13;
setImposteriser(ClassImposteriser.INSTANCE);&#13;
}&#13;
};</template><template autoinsert="true" context="java-members" deleted="false" description="Create a new JMock Mockery" enabled="true" name="mockery_for_interfaces">${:import(org.jmock.Mockery)}&#13;
private final Mockery mockery = new Mockery();</template><template autoinsert="true" context="java" deleted="false" description="Creates a @RunWith(JMock.class) declaration" enabled="true" name="run_with_jmock">${:import(org.junit.runner.RunWith,org.jmock.integration.junit4.JMock)}&#13;
@RunWith(JMock.class)</template><template autoinsert="true" context="java-members" deleted="false" description="setup a JUnit test case" enabled="true" name="setup">${:import(org.junit.Before)}&#13;
@Before&#13;
public void setUp() {&#13;
}</template><template autoinsert="true" context="java-members" deleted="false" description="Create a static setup method" enabled="true" name="setup_before_class">${:import(org.junit.BeforeClass)}&#13;
@BeforeClass&#13;
public static void setUpBeforeClass() {&#13;
}</template><template autoinsert="true" context="java-statements" deleted="false" description="print to standard out with a descriptive variable name" enabled="true" name="sysdebug">System.out.println("${word_selection}=["+${word_selection}${}+"].");${cursor}</template><template autoinsert="true" context="java-members" deleted="false" description="tear down a JUnit test case" enabled="true" name="teardown">${:import(org.junit.After)}&#13;
@After&#13;
public void tearDown() {&#13;
}</template><template autoinsert="true" context="java-members" deleted="false" description="Create a static teardown method" enabled="true" name="teardown_after_class">${:import(org.junit.AfterClass)}&#13;
@AfterClass&#13;
public static void tearDownAfterClass() {&#13;
}</template><template autoinsert="false" context="java-members" deleted="false" description="Test method (JUnit 4) for an expected exception" enabled="true" name="Test_expected_exception">@${testType:newType(org.junit.Test)}(expected = ${cursor})
public void ${testname}() throws Exception {
${staticImport:importStatic('org.junit.Assert.*')}
}</template><template autoinsert="false" context="java-members" deleted="false" description="Test method (JUnit 4) that sets a timeout" enabled="true" name="Test_timeout">@${testType:newType(org.junit.Test)}(timeout = ${cursor})
public void ${testname}() throws Exception {
${staticImport:importStatic('org.junit.Assert.*')}
}</template></templates>

2 comments:

xpmatteo said...

Hi, this is really useful! I only have a problem: when I fire the "checking" template, I get

context.checking(new Expectations() {
{

}
});

is there a way to tell Eclipse not to start a new line after the first "{" ?

Tim Myer said...

Hi xpmatteo,

Thanks for the feedback.

This is an interesting question but it is more about the code formatter than about the template itself. You have a couple of options that I can see.

1. Disable automatic code formatting for your templates (by unchecking the "Use code formatter" box on the bottom of the templates preference page).

2. Modify Preferences -> Java -> Code Style -> Formatter -> Edit... -> Blank Lines -> Before first declaration: -> 0.

(2.) would be my preference since I automatically format using save actions anyway.

If you find another way, let me know.
I hope that helps!
---Tim---