The point is missed

Museum of public mistakes and unfinished projects

Hybrid theory

with 10 comments

As I was working with JRuby recently I started wishing for some better tool integration, something that would make developing in the two languages as integrated as Java and Ruby becomes with JRuby.
When working on a particular private project I found myself developing a little in Ruby and a little in Java, switching back and forth between the two languages as needed. It makes sense to test ruby-code with RSpec and java-code with JUnit but I found it quite tedious to run two different sets of tests with two different tools and get feedback in two places.

This was not a huge problem but it did bother me. Moreover, when embedding ruby in a java-application using JRuby you find yourself in the borderland between java and ruby. In order to have your java-code run properly in JRuby you have to have the class-path properly set up both in JRuby and your java-environment (eclipse in my case).

I realized that this is a perfect opportunity to try my wings with the JUnit 4 custom runner concept. What I basically needed to do was to figure out how to make JUnit start RSpec specifications and have RSpec report back the progress to JUnit. This would give me some advantages over the curret situation:

  • Support: JUnit is supported in all kinds of different development environments not to mention build-tools like ant and maven. By making RSpec behave as JUnit I would have this support for RSpec as well
  • Options: I can choose whether I want to implement a certain functionality in Java or in Ruby, moreover, I can choose if I want to write the tests in java or ruby
  • Sell in: It may not be an option to start developing in Ruby in your current project but you may be able to test your code with ruby, a small step for man…
  • Hybrid applications: There seems to be a trend emerging to use multiple languages in systems nowadays. JRuby is an important piece in that puzzle. A tool that helps integrate java and ruby tests could lower the threshold to start integrating JRuby in your java applications just a little bit more.
  • Mocking: Mocking is integrated in RSpec, it may be the case that mocks are easier to create in Ruby syntax than in Java.

I have been doing some spiking and I think I figured out how to do it. Take a look at a classic first test:

# bowling_spec.rb
require 'bowling'
describe Bowling do
  before(:each) do
    @bowling = Bowling.new
  end
  it "should score 0 for gutter game" do
    20.times { @bowling.hit(0) }
    @bowling.score.should == 0
  end
end

This should be familiar except maybe that it is rspec code rather than JUnit code. Now I have to tell JUnit to run this spec using a custom runner:

package com.agical.jrunit.acceptance;

import org.junit.runner.RunWith;

import com.agical.jrspec.junit.JRSpecRunner;
import com.agical.jrspec.junit.JRSpecRunner.Specs;

@RunWith(JRSpecRunner.class)
public class BowlingGame {
	public static @Specs String[] specs() {
		return new String[]{"/BowlingStep1.rb"};
	}
}

Some things to notice:

  • The @RunWith annotation instructs JUnit to use a custom runner, JRSpecRunner in this case. JRSpecRunner is what I choose as a working name for my RSpec integration.
  • The @Specs annotation is used by the JRSpecRunner to determine which specs to run. The specs to run are returned as an array of strings specifying resources on the class path that contain RSpec code.

Now I can run the above test-class as I would run any JUnit test and the following error stares me in the face:

Bowling file not found

I have not yet created the bowling.rb file. To make a short story shorter. I created the bowlig.rb file and in a couple of steps made the tests pass and ended up with this:

 # bowling.rb
class Bowling
  def hit(pins)
  end

  def score
    0
  end
end

And JUnit is happier:

the first test passes

Pretty cool, lets create another example:

  it "should sum the pins of two rolls" do
	  @bowling.hit(2)
	  @bowling.hit(5)
	  @bowling.score.should == 7
  end

And JUnit tells us that we have some implementing left to do:

The second test fails

Ok, you get the point, RSpec integrated in JUnit. While that’s pretty cool for testdriving Ruby code with JRuby it doesn’t end there. What if we want to implement Bowling in Java? JRuby has some neat Java integration that helps us with that:

Change:

require 'bowling'

To:

include_class 'examples.bowling.Bowling'

And JRuby knows that Bowling is a Java-class. Skipping some steps of red bars I ended up with this Java class:

package examples.bowling;

public class Bowling {

	public void hit(int pins) {

	}

	public int score() {
		return 0;
	}
}

And JUnit says that we are in the same state as we left the ruby code in but this time we are testing a Java-class:

The same state but java this time

The only difference in the feedback is that instead of just saying “Bowling” JUnit sais Java::ExamplesBowling::Bowling which tells us that we are testing a java class and gives us a fair idea about which package it’s in. I think this stuff is pretty neat. Why not test-drive Java-classes with RSpec? It is so nice and readable. I am considering to open source this stuff to save someone else the trouble I went through to get here. What do you think? Is this a tool that You would find useful?

Written by johlrogge

September 8, 2007 at 4:58 pm

Posted in bdd, jruby, junit, Ruby, tdd

10 Responses

Subscribe to comments with RSS.

  1. I agree with you that testing Java code using Ruby is a good idea. In fact, it’s one of the things I talk about in one of my NFJS talks. If you do open source any of this stuff, drop me a line – i think it’d be quite useful.

    I am looking at figuring out how we can easily mock using JRuby (or Groovy for that matter) as well. The problem is that’s the JRuby and Groovy implementations that make them stay open despite running on the JVM start falling apart. But that’s a different matter… ;)

    Muness Alrubaie

    September 8, 2007 at 9:25 pm

  2. Thanks for your comment. I’m not quite sure what you mean with “JRuby and Groovy implementations that make them stay open despite running on the JVM start falling apart”

    Do you mean that they fill up perm-gen with unused classes until the JVM goes out of memory?

    I find this subject really interesting and I come up with new areas all the time where Ruby could complement Java and the other way around using JRuby. If you have some slides of your talk I would be interested in reading them if you can spare them. (I assume your talk is not somewhere near Stockholm :))

    I will drop you a line if and when I will open source this stuff. More comments like this and I think it will be hard for me not to do it :)

    johlrogge

    September 9, 2007 at 8:33 am

  3. This sounds really interesting! I am using JRuby for various testing, mostly functional testing, where this could be very useful.

    Btw, the theory is that test-driving one language from another is a bad idea. Since you’re driving the design of a class using TDD, and what makes a good design differs very much between languages. So at least in the low-level design you could miss the benefits of TDD. Also, the benefits of tests-as-API-documentation could also be lost when you’re mixing languages. However, I don’t think anyone has really tried these theories, since there hasn’t been that many cross-language testing tools available.

    Anders Bengtsson

    September 9, 2007 at 11:07 am

  4. @Anders – I have a similar instinct about test-driving java in Ruby, and I haven’t really experimented with it, but what you say brings up an interesting point.

    The design that we’re interested in driving out is not the internal design of the class, but rather it’s public API. I think what you say still applies, but (there’s a but), one of the initial motivations behind BDD was to pull the focus from structure to behaviour. Seems to me that using Ruby to drive out the behaviour of Java code would have some interesting implications from that perspective.

    I’ll check back in May to see your reply :)

    David Chelimsky

    January 11, 2008 at 11:00 am

  5. +1 open source! This is exactly what I need right now. Ruby/Java is really exciting, but we need to the tooling around it to get it accepted into the corporate team, and just to make our own lives easier! Please send it on? If you don’t, I’m going to write it again. :-)

    Barbara

    March 14, 2008 at 5:13 pm

  6. I wouldn’t want to force you to write it again :). My time is quite limited at the moment but I could make an effort to get it up somewhere in it’s current shape in the next few days and then we take it from there.

    Joakim Ohlrogge

    March 14, 2008 at 6:16 pm

  7. That would be absolutely brilliant! I’ll hold off so – thanks! Barbara

    Barbara

    March 19, 2008 at 10:52 am

  8. By the way, did you see this? http://pivots.pivotallabs.com/users/pzabelin/blog There might be some crossover – have you looked at running stories as well as specs?

    Barbara

    March 19, 2008 at 11:01 am

  9. Now the source is available for download. It is uploaded “as-is” here: http://sharesource.org/project/jrspec/

    If you want to play with the source you can either clone this repository with mercurial:
    http://hg.sharesource.org/jrspec/

    or just point your browser there and download a zip-file.

    The code deserves much more work than this. If anyone finds the time before I do to shape it up I would be happy to accept contributions, either by giving developer access or as patches.

    The code I just uploaded works with JRuby 1.0 that uses RSpec 1.0.5. I know that the code does not work with some later versions of RSPec due to the way JRSpec taps in to rspec.

    See RSpecIntegration in ruby/jrspec.rb for details.

    It would be nice to do away with the need to specify JRUBY_HOME and be able to run with JRuby complete.

    johlrogge

    March 21, 2008 at 3:45 pm

  10. Hi Barbara,

    Thanks for the link, it sure looks interesting. From what I understood there seems to be a big relation and some differences between what I have done and what they are doing. It looks like they are doing what I was only speculating about, using rspec to drive java-code. What jrspec does that is different from what they are doing and from what jtestr http://jtestr.codehaus.org/ does (as much as I understand) is that JRSpec runs the specs from JUnit, nothing more nothing less.

    There is one big advantage of that from how I see it and that is tool-support. Everything can run JUnit. Eclipse, Idea, Maven, Ant, Buildr, Netbeans you name it. By making your specs runnable alongside your regular JUnit tests it facilitates polyglotting, you don’t have to run two sets of tests/specs in two different tools. Everyting is a JUnit test (atleast when you want them to be)

    So I see JRSpec as complementary. Given that JRSpec can run stories as well as specs, the team in the blog would not have to solve continious integration (one thing on their todo list at the end) They would just add a jrspec-test (or a couple) to their JUnit suite and their cruiscontrol would pick it up and run it on the next check-in.

    I hope you will find the time to try out JRSpec and that it satisfies some of your needs. Good luck!

    johlrogge

    March 21, 2008 at 4:05 pm


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: