Lighter-weight Sakai development

We've recently been finding new ways to speed up development in Sakai's great-white-whale environment. I'll flesh these notes out over time, but others should feel free to chime in.

Use EasyMock 2.* for service testing

In EasyMock v2.*, the combination of Java 5 generics support, "NiceMock", and "andStubReturn()" can relieve you of the need to manually write stub implementations of external services. It's even possible to inject EasyMock-created services through Spring configurations. (Note that earlier versions of EasyMock were not as generally useful – beware out of date documentation!)

For example, let's say your code needs to refer to Sakai's CourseManagementService but you (reasonably) want to avoid the overhead and hassle of a full-blown integration test. In that case, your test code might contain something like:

private CourseManagementService cmServiceMock;
public void setUp() {
  cmServiceMock = createNiceMock(CourseManagementService.class);
  ...
}
public void testSomething() throws Exception {
  ...
  EasyMock.expect(cmServiceMock.getAcademicSession("fall08"))
    .andStubReturn(academicSessionMock);
  EasyMock.replay(cmServiceMock);

  // Now any code that asks the CourseManagementService for
  // the "fall08" term will get back the "academicSessionMock"
  // object. (You can use "andStubThrow" if you want to mock
  // up an exception.)
}

If you'd like multiple test classes to share a configuration, you could instead define the stub implementation as a normal Spring singleton bean:

  <bean id="org.sakaiproject.coursemanagement.api.CourseManagementService"
    class="org.easymock.EasyMock" factory-method="createNiceMock">
    <constructor-arg value="org.sakaiproject.coursemanagement.api.CourseManagementService"/>
  </bean>
  ...

Use TestHarness for integration testing

Unless you're testing UI interactions and view-handling code, you don't need to suffer through the complete process of shutting down and starting up a fully-loaded Tomcat every time you make a change. Try to use unit tests or project-bounded tests (with stubbed Sakai services) for your own application and component services. And when you do need to work against real Sakai services, consider using the component container emulation support in the test-harness project.

Lighten the Eclipse load

In the past, we've loaded our Eclipse workspace with hundreds of projects from Sakai trunk and maintained our Eclipse project settings by hand. That works adequately if you truly have to make simultaneous changes to source code across those hundreds of projects, but most of the time it's too much overhead. Here's an alternative approach that lets you concentrate on one or two projects at a time:

  • Use "mvn eclipse:eclipse" to automatically base lightweight Eclipse projects on your Maven pom.xml files.
  • Point a SAKAI_SRC classpath variable at your checkout of Sakai trunk so that you can continue to browse source code and set breakpoints.

Work in progress: JIRA task SAK-13484 proposes to enable this new, lighter-weight approach across the Sakai trunk.

Rapid UI development with standalone builds and jetty:run

Even a Cafe build and deployment takes a painfully long time compared to the turnarounds web developers get from PHP or Ruby-or-Rails. Although it's undeniably extra work to set up a standalone build for a project, particularly one that's targeted specifically for Sakai, it might be worth it, especially early in the development cycle, in order to get that nice "save and refresh" workflow back again.

If you do have a standalone build, extremely rapid turnaround can be obtained by ignoring Tomcat and using the "jetty:run" Maven plugin. After your first go-round, you can speed things up even more by specifying "mvn -o jetty:run".

more to come