Friday, June 19, 2009

Maven Global Excludes

To my knowledge, maven2 currently does not have the ability to globally exclude dependencies. Instead there is the tedius way of excluding a transitive dependency inline with the direct dependency (see Conflict Resolution) For complex multi-module projects, this can be difficult to manage and having the ability to exclude a dependency globally could be very useful. Seems like others share the same feelings (MNG-3196). Unfortunately, for maven2 users this is targeted for maven3. So until then, here is a tip on how to globally exclude dependencies in your project (provided by my co-worker Ron Alleva).

To globally exclude a dependency all you need to do is set the dependencies scope value to provided. This supports excluding transitive dependencies, which is really what you want.

So for example, let's assume I have a WAR project that depends on commons-logging-1.1, which according to "mvn dependency:tree" has a transitive dependency on avalon-framework-4.1.3.

[INFO] +- commons-logging:commons-logging:jar:1.1:compile
[INFO] |  +- logkit:logkit:jar:1.0.1:compile
[INFO] |  \- avalon-framework:avalon-framework:jar:4.1.3:compile
Assuming I want to exclude avalon-framework from my WAR, I would add the following to my projects POM with a scope of provided. This works across all transitive dependencies and allows you to specify it once.
<dependencies>
  <dependency>
      <artifactId>avalon-framework</artifactId>
      <groupId>avalon-framework</groupId>
      <version>4.1.3</version>
      <scope>provided</scope>
  </dependency>
</dependencies>
This even works when specifying it in the parent POM, which would prevent projects from having to declare this in all child POMs.

Monday, May 18, 2009

Ubuntu, Oracle XE, and SQLPLUS

In the past for local development, I have used MS SQL Server running in a VMware windows instance, but that got to be too burdensome and consumed to much of my 2GB of RAM (who would have thought that 10 years ago when I was playing Star Craft on a desktop with 32MB of RAM). Anyways, on a recent business trip with a co-worker (Matt White) who also runs ubuntu, he brought to my attention Oracle XE and how easy it was to install via apt-get and how small a footprint it was considering it's a database and it's Oracle.

I have been very impressed so far and would highly recommend it for linux users wanting a local database. Again, not only is it easy to install via apt-get once you add the repos, but I really don't notice it consuming too many resources.

Two hints I would like to self document more than anything is after installation the name of the SID is XE. You don't specify it during installation, but that is what it is. So my connection string in jboss looks like this:

jdbc:oracle:thin:@localhost:1521:XE

The second hint I wanted to self document is how to get sqlplus working. Personally, I'm often times too lazy to write straight SQL to manipulate data manually. Not only that but it's not a real good use of my time. But after this weekend I got familar with it again due to a lack of a good GUI tool like Oracle SQL Developer at one of our production sites. I was basically forced to use sqlplus to change a few values. The one huge benefit it has, is you don't have to wait on some slow GUI tool to load. So locally I now have, Oracle SQL Developer for extended use, got the SQL Query Plugin in Idea to use when writing code, and now sqlplus. So when I am impatient and I don't have Idea up, I plan on using sqlplus.

It doesn't work right out of the box. You have to set ORACLE_HOME and add it's bin directory in PATH and also set the ORACLE_SID.

I added the following to my home's .bashrc file:

export ORACLE_HOME=/usr/lib/oracle/xe/app/oracle/product/10.2.0/server
export ORACLE_SID=XE
export PATH=$ORACLE_HOME/bin:$PATH

After that reload the .bashrc file by running . .bashrc and then run sqlplus.

Saturday, April 18, 2009

Mock Testing with Groovy

Mock classes enable developers to quickly write unit tests that would otherwise require integration tests because of the need for a database, web container, or servlet container. Using mock classes helps to test a class in isolation and enables rapid feedback. It's not ideal to have a project with only integration tests and no unit tests. Mock classes enable unit testing that otherwise would be impossible.

So how does one create a mock class? Well, there definitely is not a shortage of mock frameworks: EasyMock, jMock, Gmock, MockFor and StubFor. You can always just create your own mock class in your test suite (which I have done in the past when in a pinch). But in my opinion these solutions lack one thing: the ability to quickly create a simple mock that when called returns what I want. To many of the mock frameworks force you to jump through hoops and call methods like expect(), replay(), verify(). What I want is the ability to define a mock class in a single line and inject it myself.

I thought MockFor and StubFor would be the solution, but the documentation is lacking and I haven't figured out how to make it work for me. Ideally I would like to say something like:

def mock = new MockFor(ICarDao.class) {
getCar: {return new Car(color: "blue")}
}
Then MockFor would mock out the remaining methods of ICarDao and now I have a mock class that implements the getCars method that when called by the Class Under Test (CUT) will return a single Car model. But MockFor doesn't work like this and neither do any of the mock frameworks to my knowledge.

There is hope however. Below you can read about 2 alternatives: groovy's metaClass and as keyword. Both require the use of groovy in your tests. If you haven't switched to using groovy to write tests yet, even for Java, then it's time to start now. There is no other framework or library that can make you more productive when writing tests. It's an instant boost.

Groovy's metaClass
As seen in this example, groovy's meta programming is very powerful. In that post I show how one can essentially mock out Thread.startDaemon() by using Thread.metaClass.static.startDaemon. Groovy's meta programming is very powerful as seen by it's heavy use in grails to make things simple. But it doesn't work in all cases.

Groovy's as keyword
Using metaClass is by far the easiest and my favorite way to create a mock class. However, this didn't work for me in my recent attempt to write some unit tests for a Java Manager class that used spring to inject a DAO that the manager used. It didn't work I believe because my Manager class never created the concrete DAO. It defines some getters and setters and expects spring to inject the concrete class. Because of this metaClass didn't work (bummer). So I did a lot of research to come up with a competitive alternative: groovy's as keyword.

Let's start by defining the Manager class:
public class CarManager {
private ICarDao dao;

public void startCar() {
Car car = dao.getCar();
.......
}

public CarManager setCarDao(ICarDao dao) {
this.dao = dao;
return this;
}
}
Now to test this using mock classes and the as keyword all you need to do is this:
class CarManagerTest extends GroovyTestCase {
def void test_start_car() {
ICarDao mock = [
getCar: {return new Car(color: "blue")}
] as ICarDao;

def cut = new CarManager().setCarDao(mock);
}
}

This uses a map and the as keyword to implement an interface. Here the key is the name of the method to mock and the value is a closure of what you want returned when called. And there is no need to define all the methods of the interface, just the ones you want to mock out.

To me, metaClass and the as keyword are much cleaner and simpler compared to the current mock frameworks. At least for this type of testing. Those frameworks might be perfectly useful for other types of testing, I just haven't ran into them yet.