Chariot Training Classes

Training Courses

I run Chariot's training and mentoring services. We provide training in AngularJS, HTML5, Spring, Hibernate, Maven, Scala, and more.

Chariot Education Services

Technology

Chariot Emerging Tech

Learn about upcoming technologies and trends from my colleagues at Chariot Solutions.

Resources

Chariot Conferences

Podcasts

Entries in SpringSource Roo (18)

Sunday
Oct212012

STS 3.1.0.RELEASE - not loving Spock / Groovy for ADJT projects

At SpringOne/2GX I tried the updated Springsource Tool Suite, 3.1.0, running a pre-4.0 Eclipse (as the STS 3.1.0 version is a bit tricky on Eclipse 4 until the 3.x - 4.0 migration bugs settle down).

Turns out there is a new error that shows up if you try to run anything Groovy within a AJDT project (which is the AspectJ Developer Tools plug-in Roo requires to compile all *.aj files when you're using them in the IDE).

You'll get:

Error compiling Groovy project: Either the Groovy-JDT patch is not installed or JavaBuilder is not being used.

I realize from talking to one of the developers at SpringOne that there have been some issues with the way Groovy handles AspectJ compiled classes, and that using Groovy within a Spring Roo project as general code it won't work properly, but this puts a damper on Spock at least from within the STS IDE. I can still run my tests from IntelliJ, however.

I'm going to post a request in the forums that we can turn off this error, so that we can use Spock for testing. So far, at least with Roo add-ons, I have used it to great effect and productivity, so at least for that use case I'd like to have an option to turn it off.

More soon.

Ken

Thursday
Jun212012

Now on java.net : my article on WebFlow and Roo from the "Cutting Room Floor" of Roo in Action

You can read my first java.net article, posted on our behalf from Manning's author articles series, entitled Spring Roo and WebFlow, on Java.Net's technical articles series starting today.

Thanks to Manning's Nermina Miller for helping me get it finished, java.net's Kevin Farnham for publishing it, and Manning's Candace Gillhooley for getting the project going.

I anticipate a few more "cutting room floor" articles, since the book took some twisty turns while Srini and I were formulating the content for the final book.

Thursday
May102012

Roo add-on development - how to unit test configuration changes

I'm working on updates to several Roo add-ons, which I am going to be pushing out to the Roo repository soon. Here are some challenges and how I overcame them.

The add-on command marker interface

This add-on sets up Coffeescript using a Maven plugin. Here is the add-on source:

package org.sillyweasel.addons.coffeescript;

import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.Service;
import org.springframework.roo.shell.CliAvailabilityIndicator;
import org.springframework.roo.shell.CliCommand;
import org.springframework.roo.shell.CliOption;
import org.springframework.roo.shell.CommandMarker;

@Component
@Service
public class CoffeescriptCommands implements CommandMarker { 

  /**
   * Get a reference to the CoffeescriptOperations from the underlying OSGi
   * container
   */
  @Reference
  CoffeescriptOperations operations;

  @CliAvailabilityIndicator({"coffeescript setup"})
  public boolean isSetupCommandAvailable() {
    return operations.isSetupCommandAvailable();
  }

  @CliAvailabilityIndicator({"coffeescript remove", "coffeescript addjoinset", 
    "coffeescript removejoinset", 
    "coffeescript listjoinsets"})
  public boolean isCoffeescriptInstalled() {
    return operations.isPluginInstalled();
  }

  @CliCommand(value = "coffeescript setup", 
     help = "Install the CoffeeScript compiler")
  public void setup(
    @CliOption(key = "outputDirectory", mandatory = false,
        unspecifiedDefaultValue = "${project.build.directory}") String outputDirectory,
    @CliOption(key = "coffeeDir", mandatory = false,
        unspecifiedDefaultValue = "src/main/webapp/scripts",
        specifiedDefaultValue = "src/main/webapp/scripts") String coffeeDir,
    @CliOption(key = "bare", mandatory = false,
        unspecifiedDefaultValue = "false",
        specifiedDefaultValue = "true") boolean bare) {

    operations.setup(coffeeDir, outputDirectory, bare);
  }

  public void addJoinSet(
      @CliOption(key = "joinSetId", mandatory = true, specifiedDefaultValue = "main")
      String joinSetId,
      @CliOption(key = "includes", mandatory = true, 
         help = "comma-separated list of search paths for javascript files to include")
      String includes,
      @CliOption(key = "excludes", mandatory = true, 
         help = "comma-separated list of search paths for javascript files to exclude")
      String excludes) {

    // TODO - set up the command

  }

  @CliCommand(value = "coffeescript remove", help = "Remove the coffeescript compiler")
  public void remove() {
    operations.remove();
  }
}

Some of this I haven't written yet (hence the TODOs) but the rest is fleshed out and I'll be going over it later.

Task #1 - Roo addons don't include JUnit?

Right now, no. (ROO-3161) However, you can just add it yerself. I'm using Mockito for mocking (more about that later) as well as messing around with those lovely Hamcrest matchers:

<dependency>
  <groupId>junit</groupId>
  <artifactId>junit</artifactId>
  <version>4.10</version>
  <scope>test</scope>
</dependency>
<dependency>
  <groupId>org.hamcrest</groupId>
  <artifactId>hamcrest-all</artifactId>
  <version>1.1</version>
  <scope>test</scope>
</dependency>
<dependency>
  <groupId>org.mockito</groupId>
  <artifactId>mockito-all</artifactId>
  <version>1.9.0</version>
  <scope>test</scope>
</dependency>

Task #2 - You need to widen the visibility of the Roo-injected OSGi objects to mock them

Because we want to unit test our add-ons without firing up an OSGi container, we will need to mock things. I'm using Mockito, an excellent mock and spy library. But I can't get to the injected objects, and the test I'm going to show here has to make a "mockery" of the ProjectOperations Roo service. It is defined this way in the code of the Operations implementation class:

private @Reference ProjectOperations projectOperations;

The problem with this is that I can't just use Mockito's mocking method to access and fake it out. So, I widened to friendly scope, which allows access from the same package. I guess the better way would maybe have been to create a getter but then I'm exposing it in a wider range than just the add-on's specific package:

@Reference ProjectOperations projectOperations;

Task #3 - how to test the Command Marker

Ok, so the first thing I want to do is make sure my Command Marker calls the proper command implementation methods. First up, we widen the reference to our CoffeescriptOperations variable:

@Reference CoffeescriptOperations operations;

Then, we write a method that uses Mockito to mock calls to the operations object. This is the test class:

package org.sillyweasel.addons.coffeescript;

import junit.framework.Assert;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;

import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.mockito.Mockito.*;

public class CoffeescriptCommandsTest {

  private CoffeescriptCommands commands;

  @Before
  public void setUp() {
    commands = new CoffeescriptCommands();
    commands.operations = mock(CoffeescriptOperations.class);
  }

  @Test
  public void testIsPluginInstalled() {
    when(commands.operations.isPluginInstalled()).thenReturn(false);
    assertThat(commands.isCoffeescriptInstalled(), is(false));
  }

  @Test
  public void testIsCoffeescriptSetupAvailable() {
    when(commands.operations.isSetupCommandAvailable()).thenReturn(true);
    assertThat(commands.isSetupCommandAvailable(), is(true));
  }

  @Test
  public void testIsCoffeescriptRemoveAvailable() {
    when(commands.operations.isPluginInstalled()).thenReturn(true);
    assertThat(commands.isCoffeescriptInstalled(), is(true));
    verify(commands.operations, times(1)).isPluginInstalled();
  }

  @Test
  public void testInstallCoffeeScript() {
    commands.setup("foo", "bar", true);
    verify(commands.operations).setup("foo", "bar", true);
  }

  @Test
  public void testRemoveCoffeeScript() {
    commands.remove();
  }

  @Test
  @Ignore
  public void testFileSets() {
    Assert.fail();
  }
}

See how I'm using some Hamcrest matchers in there? I like assertThat(..., is()) syntax.

So now we know that our command marker is actually calling the delegate methods when it is being invoked. And we're on our way, able to mock anything we want to, provided we widen the scope a bit from a 100% internal private member variable.

In our next post I'll show you how to test the actual XML configuration. That one is going to be rather large so I'll separate it into another one.

Sunday
Jan082012

Roo, Selenium WebDriver,Failsafe and JUnit - Smores, anyone?

S'Mores are about the perfect mix of sugar, sugar and chocolate. So, the programming equivalent would be getting your Selenium tests separated from your unit tests, and running in an API that just needs a web server, not a separate Selenium server, right?

(Ok, I'm stretching it).

A WebDriver test

First, here is an integration test, ITCourseSelenium.java that uses the Selenium WebDriver API. Look how simple the code is:



Next up, we have the Maven configuration for the various plugins to install Selenium (forget the current Selenium Roo add-on for this, it only sets up HTML tests and doesn't include the Java API, plus doesn't install WebDriver and needs to run on a port, which is tricky):

Selenium Configuration

Add these elements to your pom.xml file to set up the configuration:



These fragments configure a jetty web server, which starts up before integration testing. They also configure the maven-failsafe-plugin, which is attached to the integration-test and verify Maven lifecycle phases.

Running the tests

To run your tests, just issue the mvn verify command. All tests starting or ending with IT will run after the web application starts, and will be recorded as test results in target/failsafe-reports.

Enjoy.

Ken

Tuesday
Oct182011

Roo (in the) Corner - new features in trunk...

I've been spending my time readying Roo in Action for publication. Turns out, the Roo team had other ideas - including lots of new things you may want to be aware of if you are looking to support Roo 1.2 once it is released.

Keep in mind these changes are in-flight. If you don't need to work on trunk, DO NOT WORK ON TRUNK. This is something other platform afficianados do - for example, the Rails development community commonly calls this working on the "edge". So, let's get edgy.

There are some really, really cool things in here. I've seen them move toward opening up for all modes of development - some want JSF, so there is a JSF add-on. They use PrimeFaces, and a dialog motif for adding new elements. I'm sure they will tweak this as it goes along, but it looks more like the GWT or Flex mode of editing I saw before.

Breaking Changes (so far) - you may need to edit your code - I know I have to for now, but this is a temporary pain for some consistency gain within Roo.


  • @RooEntity -> @RooJpaActiveRecord

  • @RooWebScaffold - now a .scaffold. package after .controller.

  • @RooConversionService - now a .converter. package after .controller.


Additions


  • New @RooEquals - and a shell command for equals - this has been here for a little while, but is something that can be of use when defining models or other objects that need to be compared. You can exclude fields from the factoring of the comparison.

  • new entity flags (recent anyway) to set entity name, table, and other attributes on entities - this is great, and includes the ability to define transaction manager names for cases where you are working with multiple JDBC datasources - nice! Also, it lets you specify the entity manager - so if you have two persistence units to separate transaction managers (reporting database -vs- transactions) you have that option. Again, not a huge deal, but lets you stay within Roo to get things done, without digging into code for a configuration option. You can even set the table name, entity name, etc...

  • New settings for the json command - --deepSerialize and --rootName - I am not sure if these have been here long, but they are good to know about.

  • New —packaging element in project - includes POM or JAR right now. Also includes --parent. This could be great, as I think they are going to implement multi-pom support in Roo 1.2. We'll stay tuned on that, and perhaps write a quick blog entry on what we've found.

  • New support for database dot com - a new database provider - I don't know much about it.

  • New date field support for both dateTimeFormatPattern AND dateFormat - I am unsure that the scaffold would deal with dateTimeFormatPattern.

  • JSF scaffolding in place - uses PrimeFaces for the widgets - this is interesting, and has a different look and feel, native to PrimeFaces. But, it does exactly the same work as the scaffold in MVC. So, if you're looking at complexities and benefits of each, go for it. The CI build server is here, and you just need to follow these rules to get it to use trunk.


It was so easy to switch between JSF and MVC for my testing, I used these two scripts:

Roo with MVC

 

project --topLevelPackage foo.bar.mvc --packaging JAR --projectName mvcrules
jpa setup --database HYPERSONIC_PERSISTENT --provider OPENJPA
entity jpa --class ~.model.Course --testAutomatically
field string --fieldName name
field date --fieldName runDate --type java.util.Date --dateFormat SHORT
web mvc setup
web mvc all --package ~.mvc quit
Roo with JSF
project --topLevelPackage foo.bar.jsf.sortarules --packaging JAR --projectName jsfsortarules
jpa setup --database HYPERSONIC_PERSISTENT --provider OPENJPA
entity jpa --class ~.model.Course --testAutomatically
field string --fieldName namefield date --fieldName runDate --type java.util.Date --dateFormat SHORT
web jsf setup
web jsf all --package ~.jsf quit

I will attempt to update this article as I find new things... No promises, as the primary artifact is the book. But hopefully this is a warning shot across the bow that change is indeed a-coming.