Wednesday, January 14, 2015

Configure Maven for JUnit, Hamcrest, and FitNesse

Exceptionally readable, maintainable unit- and integration- tests can be implemented using the JUnit and Hamcrest APIs. Business requirements (preferably captured as user stories) can be mapped to acceptance tests using the wiki-based FitNesse framework.  The merits of test- and acceptance- driven development is becoming mainstream in agile development shops but if you're not familiar with these concepts I highly recommend reading the books I've listed at the end of this post.

Here's an example Maven configuration to add these tools to a project:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

  <modelVersion>4.0.0</modelVersion>


  <groupId>MyGroupId</groupId>

  <artifactId>MyArtifactId</artifactId>

  <version>MyVersion</version>

  <packaging>jar</packaging>


  <name>MyProjectName</name>

  <url>http://maven.apache.org</url>


  <properties>

    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
     
    <versions.junit>4.12</versions.junit>

    <versions.hamcrest-library>1.3</versions.hamcrest-library>
    
    <versions.fitnesse>20140901</versions.fitnesse>

  </properties>


  <dependencies>

    <dependency>

      <groupId>junit</groupId>

      <artifactId>junit</artifactId>

      <version>${versions.junit}</version>

      <scope>test</scope>

    </dependency>

    <dependency>

      <groupId>org.hamcrest</groupId>

      <artifactId>hamcrest-library</artifactId>

      <version>${versions.hamcrest-library}</version>

      <scope>test</scope>

    </dependency>

    <dependency>

      <groupId>org.fitnesse</groupId>

      <artifactId>fitnesse</artifactId>

      <version>${versions.fitnesse}</version>

    </dependency>


  </dependencies>

</project>

Write your unit and integration tests using the JUnit and Hamcrest APIs.  Turn requirements into executable acceptance tests using the FitNesse wiki pages its SLiM API.  Don't forget to check for newer versions of these libraries at mvnrepository.com:

You can run the FitNesse server from your IDE with the following configuration (IntelliJ IDEA is used as an example):


I like to launch FitNesse on port 8181 rather than 8080 because I usually have some other application, such as Tomcat, listening to that port.

Suggested Reading
  • ATDD by Example: A Practical Guide to Acceptance Test-Driven Development (Markus Gartner)
  • Growing Object-Oriented Software, Guided by Tests (Steve Freeman, Nat Pryce)
  • The Art of Unit Testing, Second Edition: with examples in C# (Roy Osherove)
  • Clean Code: A Handbook of Agile Software Craftsmanship (Robert C. Martin)

Thursday, March 29, 2012

Project synchronization problems with Spring Roo and SpringSource Tool Suite

While working through Spring Roo In Action I encountered synchronization problems between the SpringSource Tool Suite (STS) and Spring Roo.  For example, if you use the STS Roo Project Wizard to create a new project with POM packaging the resulting project's Problems view reports missing source code folders. If you use the Roo shell to create a module the STS does not create an Eclipse project for it. If you use the Maven plugin to create a new Maven module for your Roo project, your project becomes somewhat corrupted. If you import a multi-module Roo project the parent Eclipse project is missing Roo Project Nature. 


These issues were experienced using the following configuration:
  • STS version 2.9.1
  • Spring Roo version 1.2.1
  • Maven 3.0.3
  • Java 1.6.0_b29
  • OS X 10.6.8
Multi-module project support in Roo is relatively new so I'll assume the STS team is still playing catch-up.  To assist them or anyone else interested in replicating these anomalies I've documented step-by-step procedures in this article.  But first, I'll describe a few rules we can follow to avoid these problems.


If you want to create a new Roo project:
  1. Create your new project using an external Roo shell.
  2. If this is a multi-module project, create the child modules.
  3. If applicable, setup your JPA configuration.
  4. Create at least one Java class and its associated test cases (use the --testAutomatically option).*
  5. Import your Roo project as an existing Maven project.
  6. If this is a multi-module Maven project, add Roo project nature to the parent module.**
  7. For any new modules created, import them into the STS as existing Maven projects.
*If you skip this step, you will have to explicitly configure your source folders in the STS after creating your Java classes and test cases.  Without source folders configured you will not be able to use certain STS features including push-in refactoring and auto import.  You'll notice the Package Explorer will not let you expand Java class or ITD nodes in its tree.
**This will allow you to open a single Roo shell in the STS for the parent and then change focus to any child module.

If you want to check out a Roo project from source control:
  1. Use the STS to import the project from the source control server.

The rest of this article will describe step-by-step procedures to replicate the problems I encountered.

Problem: You created a project using the STS Roo Project Wizard.  After creating your first Java class you notice certain STS features including push-in refactoring and auto-import aren't available.

Workaround: Configure your Eclipse project's build path to include src/main/java and src/test/java.

Follow these steps to demonstrate the problem and workaround:
  1. In the STS IDE select File->New->Spring Roo Project.
  2. Enter foo in the "Project name" field.
  3. Enter com.acme.foo in the "Top level package name" field.
  4. Click the Next button.
  5. Click the Finish button.
  6. Open the Problems view if it is not already open.
  7. Observe there is nothing reported in the Problems view.
  8. Observe in the Package Explorer view that the foo project icon is adorned with the graphics for both the Java and Maven project natures.
  9. Expand the foo project node in the Package Explorer view.
  10. Observe the STS has configured src/main/resources as a source code folder.
  11. Open the Navigator view.
  12. Observe the src/main/resources folder does not exist (the wizard only created src/main)!
  13. In the STS Roo shell type jpa setup --database HYPERSONIC_IN_MEMORY --provider HIBERNATE
  14. In the Roo shell type: entity jpa --class ~.model.Bar --testAutomatically
  15. In the Package Explorer, observe Roo has created the Bar entity, test classes, and associated ITD files (if you don’t see the ITD files in the Package Explorer, click the triangular symbol in the upper right-hand corner of the Package Explorer and select “Filters...”, then deselect the option “Hide generated Spring Roo ITDs”).
  16. Observe that Roo has created the new source files under src/main/java and src/main/test BUT THE STS PACKAGE EXPLORER DOES NOT SHOW THESE AS SOURCE FOLDERS.
  17. In the Roo shell type perform tests
  18. Observe all tests pass.
  19. In the Roo shell type field string --fieldName pinNumber --sizeMin 4 --sizeMax 4 --regexp "[0-9]{4}"
  20. In the Roo shell type perform tests
  21. Observe the tests fail because the the values being injected into the Bar instance's pinNumber field do not satisfy the validation rules we defined for it.
  22. We need to “push-in” refactor the BarDataOnDemand.setPinNumber method to generate a 4-digit string.  Observe that you cannot expand source code nodes in the Package Explorer view.  The STS Project has not kept up with our project configuration changes made in the Roo shell.  In my opinion STS should have been notified that we now have source code in our project and instructed to add the source folders to the Eclipse project's build path.  We need to tell the STS where our source code folders are so we can do our refactoring.
  23. In the Package Explorer view right-click the src/main/java folder.
  24. Select Build Path->Use as source folder
  25. Do the same for the src/test/java folder.
  26. Expand the src/test/java->com.acme.foo.model->BarDataOnDemand_Roo_DataOnDemand.aj node
  27. Right-click the BarDataOnDemand.setPinNumber(Bar, int) node
  28. Select Refactor->Push In...
  29. Click the OK button.
  30. Open the BarDataOnDemand java source file.
  31. Modify the code as follows:
  32. public void setPinNumber(Bar obj, int index) {
  33.    StringBuffer pinNumber = new StringBuffer();
  34.    pinNumber.append(Integer.toString(new Random().nextInt(10)));
  35.    pinNumber.append(Integer.toString(new Random().nextInt(10)));
  36.    pinNumber.append(Integer.toString(new Random().nextInt(10)));
  37.    pinNumber.append(Integer.toString(new Random().nextInt(10)));
  38.    obj.setPinNumber(pinNumber.toString());
  39. }
  40. In the Roo shell, type perform tests
  41. Observe all tests pass.
  42. Close the foo project.
After you do certain tasks inside a Roo shell you have to tell the STS what you've done so it can stay in sync with the changes.  Once we updated the STS build path we gained access to the refactoring capabilities one normally expects to be available after a new project wizard has creates a project.  Clearly there is room for improvement with regards to how the STS and Roo communicate events.

Problem: You created a project with POM packaging using the Roo Project Wizard because you want to use Maven modules.  The resulting Eclipse project has errors reported in the Problems view.

Workaround: Remove the invalid <classpathentry> elements from the .classpath file and then create your child modules with the STS Roo shell.


Follow these steps to demonstrate the problem and workaround:
  1. In STS select File->New->Spring Roo Project.
  2. Enter foo2 in the "Project name" field.
  3. Enter com.acme.foo in the "Top level package name" field.
  4. Select POM in the Packaging drop-down.
  5. Click the Next button.
  6. Click the Finish button.
  7. Open the Problems view if it is not already open.
  8. Observe the following problems reported in the Problems view:
  9. Project 'foo2' is missing required source folder: 'src/main/java'
  10. Project 'foo2' is missing required source folder: 'src/main/resources'
  11. Project 'foo2' is missing required source folder: 'src/test/java'
  12. Project 'foo2' is missing required source folder: 'src/test/resources'
  13. The project was not built since it depends on foo2, which has build path errors foo2 Unknown Java Problem
  14. Use the Navigator view to open the project's .classpath file.
  15. Observe the STS has created <classpathentry> elements for the missing folders.
  16. Delete these elements (the first four in the document) and save the file.
  17. Observe the Problems view still reports the following error: unable to find org.aspectj.lang.JoinPoint (check that aspectjrt.jar is in your classpath)
  18. In the STS Roo shell type module create --topLevelPackage com.acme.foo --moduleName foo2-core
  19. Observe the Problems view no longer reports any errors.
  20. Quit both Roo shells.
  21. Close the foo2 and foo2-core projects.
The STS Roo Project Wizard created an invalid project configuration.  The STS team should take measures to prevent this from ever happening.  Things get even worse if you mistakenly try to create new modules using the STS Maven plugin's New Maven Module function.  Don't do it, as you'll end up with some really screwed up behavior:

Problem: You created a project with POM packaging using the Roo Project Wizard because you want to use Maven modules.  Instead of creating your child modules with the Roo shell, you did so using the STS Maven plugin. As a result, you have problems switching focus between modules in the Roo shell.

Workaround: When working with Roo projects, always use the Roo shell to create your modules and then import them into the STS.



Follow these steps to demonstrate the problem:
  1. In the STS IDE select File->New->Spring Roo Project.
  2. Enter foo3 in the "Project name" field.
  3. Enter com.acme.foo in the "Top level package name" field.
  4. Select POM in the Packaging drop-down.
  5. Click the Next button.
  6. Click the Finish button.
  7. Right-click the foo3 project node in the Package Explorer view.
  8. Select Maven->New Maven Module Project
  9. Enter foo3-core in the Module Name field.
  10. Select the Create Simple project (skip archetype selection) check box.
  11. Click the Next button.
  12. Click the Finish button.
  13. Right-click the foo3-core node in the Package Explorer view.
  14. Select Spring Tools
  15. Observe that the project does not have Roo project nature.
  16. In the foo3 Roo shell type module focus --moduleName foo3-core
  17. Observe the Roo shell reports Command 'module focus --moduleName foo3-core' was found but is not currently available (type 'help' then ENTER to learn about this command)
  18. Roo will not allow us to switch modules at this time because it doesn't know we used the STS to create a child module.  The STS needs to communicate these kinds of events to Roo.
  19. Close the foo3-core project.
  20. Delete the foo3-core project (including contents on disk).
  21. Quit the foo3 Roo shell, then open it back up.
  22. Type module create --topLevelPackage com.acme.foo --moduleName foo3-core
  23. Observe the Roo shell reports Command 'module create --topLevelPackage com.acme.foo --moduleName foo3-core' was found but is not currently available (type 'help' then ENTER to learn about this command)
  24. Open the foo3 project's pom.xml file.
  25. Observer the STS reports a NullPointerException.
  26. At this point it appears the STS did something to corrupt foo3 project.  I don't have an answer as to what happened, but clearly we can damage our project if we use the Maven plugin to create child modules.
  27. Close the foo3 project.
The point of this exercise was to demonstrate how you can get yourself into trouble using features of the STS that you assume will place nice with Roo.  Let's look at the procedure I recommend for starting a new Roo project.

Problem: You want to create a Roo project and then do most of your work using the STS.

Solution: Use an external Roo shell to create your modules, JPA configuration, and at least one Java class before importing the project into the STS.

  1. From your command console navigate to your STS workspace folder and type mkdir foo4; cd foo4; roo
  2. Type project --topLevelPackage com.acme.foo --packaging POM --projectName foo4
  3. Type module create --topLevelPackage com.acme.foo --moduleName foo4-core
  4. Type jpa setup --database HYPERSONIC_IN_MEMORY --provider HIBERNATE
  5. Type entity jpa --class ~.model.Bar --testAutomatically
  6. Type field string --fieldName pinNumber --sizeMin 4 --sizeMax 4 --regexp "[0-9]{4}"
  7. Type quit
  8. Import the project into STS as an existing Maven project.
  9. Observe that STS creates Eclipse projects for foo4-core and foo4.
  10. Observe the STS has correctly identified the source folders of foo4-core
  11. Observe the STS Roo shell's bottom tab label is associated with foo4-core. ALSO NOTE that the shell's prompt DOES NOT show the focus at foo4-core, but instead it is roo.  I consider this to be a bug, as the prompt should always indicate the active focus.
  12. Observe the STS has not added Roo project nature to foo4.  Why is this? I think it's another bug in the STS.  It should know to do this and should have opened our Roo shell with focus on the parent module, foo4.
  13. Type entity jpa --class ~.model.Baz --testAutomatically
  14. Observe the new entity was created in the foo4-core project, confirming the Roo shell has focus on the foo4-core project.
  15. Add Roo Project Nature to the foo4 project.
  16. Open a second Roo shell for the foo4 project.
  17. In the foo4 Roo shell type module focus --moduleName foo4-core
  18. Observe the shell prompt indicates focus changed to the foo4-core module.
  19. Change focus back to the parent module: module focus --moduleName ~
  20. Let's create a new module: module create --topLevelPackage com.acme.foo --moduleName foo4-web
  21. Observe the module is created by Roo, but the STS did not create a new Eclipse project for the module.
  22. Select the foo4 project in the Package Explorer view.
  23. Select File->Import...->Maven->Existing Maven Projects
  24. Observe the STS has pre-selected the foo4-web project to be imported.
  25. Click the Finish button.
  26. Observe the STS creates a new foo4-web Eclipse project and opens a roo shell for it.
  27. In the foo4-core Roo shell type module focus --moduleName ~
  28. Observe Roo complains the command is not available.  Observe the same behavior occurs in the foo4-web shell (it too, doesn't know about it's parent). 
  29. This behavior is consistent with how Roo works.  If you open a Roo shell for a child module it does not have any context about its parent.  This is why I prefer to add Roo nature to the parent module so I can easily switch between modules.  The STS, in its current design, wants you to use a separate Roo shell for each child module and none at all for the parent.  I find this less than optimal.
  30. Close the foo4, foo4-core, and foo4-web projects in the STS.
In summary I recommend you follow the rules I posted at the beginning of the article and avoid trying to use the STS to make structural changes to your Roo project. Use the Roo shell to create new modules as needed and then import them as Existing Maven Projects.

If you have had different experiences or know of better workarounds, or if you see a problem with the way I assume the STS tool is intended to work with Roo, please add your comments.

Friday, May 20, 2011

Core Spring Certification

Passing the Core Spring 3.0 Certification exam is challenging but well within reach if you take a few weeks to prepare for it. If you've passed the Sun Java Certified Programmer exam, you'll probably find that preparing for the Spring exam requires much less work (the SJCP exam has much more breadth to it).

Preparing for the Exam

My preparation consisted of taking the four day course (required for all students), 2 weeks to redo all the labs, and 2 days of mock exam testing.

Specifically, here's how I prepared:
  1. I reviewed Jeanne Boyarski's blog about her exam study preparation.
  2. I created my own study guide, using the Core Spring 3.x Certification Study Guide as an outline.
  3. As I reviewed each class slide, I updated my study guide with the relevant information.
  4. I completed all of the course labs for a second time to help reinforce concepts.
  5. I took the Skill Guru Core Spring 3.0 Mock Exam 2 several times.
  6. I took the Skill Guru Core Spring 3.0 Mock Exam 1 several times.
  7. I reviewed sections of the Spring Reference Documentation relevant to sections of the mock exams I had difficulty with.
  8. I reviewed Gavin Laznitzki's exam study guide.
I've never been a great test taker and the first time I took Mock Exam 2 I scored a lousy 56%. Fortunately, Skill Guru allows you to retake a test as many times as you want after the initial purchase of just a few dollars. I took it a second time, consulting the Spring Reference Documentation and the Spring JavaDoc API if I wasn't 100% sure of the answer. A few of the questions on the mock exams are not in scope of the real test but I think they alert you to important concepts you'll want to know anyway. On my second pass I achieved 85%. After several iterations I was scoring into the high nineties.

Taking the Exam

I arrived at the test center 30 minutes before my exam was scheduled but it only took a few minutes to sign in so I began the test early. You're provided with a small dry-erase board and pen, which I only used to write down question numbers I wasn't too sure of the answer. The exam software allows you to flag a question for review at the end of the test. Generally you can use deductive reasoning to eliminate one or two answers to a multi-answer question, and in some cases questions give you clues to answers on other questions. But you really do need to know your stuff, because you can only get 12 questions wrong. By far, container basics and AOP are the majority of the test, so spend most of your time studying these sections. Transactions, Spring-MVC, JMS, JMX, and Security were also covered, but only a few questions each in those areas.

When I took the SJCP, I was sweating towards the end because it had taken me several months to get ready and I just wanted to be done with it. I had much less time invested in preparing for the Spring test, but I didn't relish the thought of having to cough up $150 to retake it if I failed. I had reviewed all the questions, a few of which offered vague choices, but I couldn't justify changing any of my answers so I submitted the test for a final score. I got 44 out of 50 correct (88%) and I'm satisfied with that.

After I finished I was given a print-out of my score, which shows you what percentage you got correct in each section. I should be receiving a soft-copy of the certificate via e-mail in a week or so.

Spring is a huge API, and there's no way anyone can master it all but I found the training and certification experience quite valuable. I've already begun applying the concepts and best practices I learned to the projects I'm working on. If you're fortunate enough to have an employer that will pay for the training, I highly recommend it. In my situation, I paid for this out of my own pocket, and feel it was worth every penny.

Monday, March 21, 2011

Core Spring Training

Last week a colleague and I attended Core Spring Training in El Segundo. Both of us have been working with the Spring framework for about a year and a half but even after all that time we've just scratched the surface of what it offers developers. We both want to get certified, and attending the official SpringSource training course is a prerequisite to taking the test. The commute from Irvine to LAX was awful. The course was awesome!

We lucked out with a small class - a total of four students and two instructors. Each student receives course slides, a lab workbook, a notepad and a soft copy of course materials on a USB flash drive. Included is a pre-configured version of the SpringSource Tool Suite (STS) with the course labs ready to go. You can load your PC or Mac with a complete reproduction of the course development environment. The instructors were very knowledgeable of the material and shared a lot of their personal experiences solving problems with Spring.

I paid for this course out of my own pocket and it was well worth it. I'll be able to immediately apply what I learned to new work underway at my current consulting gig, particularly with respect to transaction management and security.

I'll be studying for the test over the next few weeks...will update the blog here with my experience after taking the test.