Spock @RunJetty
Join the DZone community and get the full member experience.
Join For Free
working with
geb
is fun especially when integrated with
spock
. in order to write tests for a tapestry app, i wanted to have something on the lines of
seleniumtestcase
which will automatically start and stop a jetty server. so i ended up writing a spock plugin for running jetty.
we start with the annotation(why do i always start with an annotation ?
)
@documented @retention(retentionpolicy.runtime) @target({elementtype.method, elementtype.type}) @extensionannotation(jettyextension.class) public @interface runjetty { string context() default ""; int port() default 9090; string webappdirectory() default "src/main/webapp"; string host() default "localhost"; }
note the annotation @extensionannotation(jettyextension.class). it tells spock what extension to use for this annotation.
public class jettyextension extends abstractannotationdrivenextension<runjetty> { private boolean isspecannotated; @override public void visitspecannotation(final runjetty runjetty, specinfo specinfo) { isspecannotated = true; specinfo.addlistener(new abstractrunlistener() { private server server; @override public void beforespec(specinfo specinfo) { server = jettyutils.run(runjetty.context(), runjetty.webappdirectory(), runjetty.port()); } @override public void afterspec(specinfo specinfo) { jettyutils.stop(server); } }); } @override public void visitfeatureannotation(final runjetty runjetty, featureinfo featureinfo) { if(isspecannotated){ throw new runtimeexception(string.format( "a single specification cannot have both specification and feature annotated " + "by %s", runjetty.class.getsimplename())); } featureinfo.getparent().addlistener(new abstractrunlistener() { private server server; @override public void beforefeature(featureinfo featureinfo) { server = jettyutils.run(runjetty.context(), runjetty.webappdirectory(), runjetty.port()); } @override public void afterfeature(featureinfo featureinfo){ jettyutils.stop(server); } }); } } public class jettyutils { public static server run(string contextpath, string webappdirectory, int port) { server server = new server(port); socketconnector connector = createconnector(port); server.setconnectors(new connector[]{connector}); webappcontext context = createwebappcontext(webappdirectory, contextpath); server.sethandler(context); try { server.start(); } catch (exception e) { throw new runtimeexception("could not start a jetty instance: " + e.getmessage(), e); } return server; } public static void stop(server server){ try { server.stop(); } catch (exception e) { throw new runtimeexception("could not stop a jetty instance : " + e.getmessage(), e); } } private static webappcontext createwebappcontext(string webappdirectory, string contextpath) { webappcontext context = new webappcontext(); context.setwar(webappdirectory); context.setcontextpath(contextpath); return context; } private static socketconnector createconnector(int port) { socketconnector connector = new socketconnector(); connector.setport(port); return connector; } }
if the annotation is placed on a spec, this extension starts the server before a spec and stops it after all the features in the spec are run. if the annotation is placed on a feature, the server is started before the feature and stopped after the feature.
now to make the extension work with gebspec we have to make a few changes which we do by extending gebspec.
@runjetty class jettygebspec extends gebspec { def setup() { runjetty runjetty = getrunjettyannotation() browser.baseurl = "http://${runjetty.host()}:${runjetty.port()}/${runjetty.context()}" } protected runjetty getrunjettyannotation() { runjetty runjetty = this.class.getannotation(runjetty); if (runjetty == null) { runjetty = jettygebspec.getannotation(runjetty.class); } return runjetty; } }
this base class sets the baseurl for geb and also sets the defaults for @runjetty. so now you can write a geb spock test like this.
public class mytest extends jettygebspec { def "test my page"(){ given: to indexpage } }
Published at DZone with permission of Taha Siddiqi, DZone MVB. See the original article here.
Opinions expressed by DZone contributors are their own.
Trending
-
From CPU to Memory: Techniques for Tracking Resource Consumption Over Time
-
Avoiding Pitfalls With Java Optional: Common Mistakes and How To Fix Them [Video]
-
RBAC With API Gateway and Open Policy Agent (OPA)
-
Seven Steps To Deploy Kedro Pipelines on Amazon EMR
Comments