Infinitest for Java, have you tried it? 10
Background
About 2 years ago, I was working with Ben Rady and he demonstrated something he was working on at the time: Infinitest. As often I am, I was a little interested but mostly skeptical – don’t know if that came across or not.Since then he and others (e.g., Rod Coffin have made amazing strides and created plugins for both Eclipse and IntelliJ.
Taking it for a test run
Earlier this month, I finally decided to give it a test drive. When I made that announcement, Ben made the following (bold?) statement:For me, using Infinitest is as different from TDD as TDD is from not testing
So is that true? Is using a continuous test execution tool as different from not using one as using TDD is from not testing? I’m not sure I’m there yet. However, I will say my brain is having some difficulty getting used to the cool feedback.
Here are two recent experiences I had using it.
Classpath Issues
Back at the end of 2006 I wrote a class on using JPA and EJB 3. I’ve not really done much to update that material in some years but recently I had an email from someone trying to work through the first tutorial with little success. Over the past few years there’s been some bit-rot. The embeddable container is not really up to date, EJB 3.1 includes an embeddable container as part of its spec, Hibernate has been updated, etc. So I spent a few hours tracking down updated jar files and building my classpath. I had already installed Infinitest and I noticed as added I something to my classpath, Infinitest would kick off and show a stack trace (my code was doing that in a @Before method). So I sped up what I was doing:- I directly edited the .classpath file in Eclipse
- Saved what I was doing
- Waited about a second
- Noticed the new stack trace
- Found the next jar file I needed to add
- Repeat until tests passed.
Might sound like a bit of overkill, but in the end I built a classpath from scratch and I ended up adding 13 jar files. So it saved some time.
Note, I wasn’t looking for this. I had only installed Infinitest the day before so this was unexpected and welcome! Oh, and before my @Before method was handling the exception properly, Infinitest showed that the code had a problem (it was in the @After with a null pointer exception), which it indicated as an error like a syntax error or a validation error. Nice!
Using Mockito
I’ve recently been using Mockito. You can review a previous blog entry for that example. Today we’re holding the first coding dojo at the recently opened OkC CoCo. Last night I started working on the next problem I want to use for the next dojo. It involves practicing using a mockist approach. I set up my classpath, started writing tests and immediately I noticed what looked like a syntax error on the verification step of my first unit test. I was confused thinking I had an actual syntax error since I’m not quite to the point of touch-typing Mockito based tests (I did update Eclipse so I could more easily find the static imports).Next, I updated my test to use the @Mock annotation. I removed the hand-written initialization and immediately I noticed a “syntax” error – null pointer exception. I was immediately (OK 1 second later) showed the impact of removing a single line of code. I added the missing line to auto-initialize the @Mock annotated fields but I did it incorrectly, so the error remained. I finally got the line correct and the “syntax error” went away.
Observations
Wow. That’s what I have to say so far. I’m not entirely sure the before and after of using Infinitest is the same size as moving from not testing to using TDD. Maybe it’s the same as moving from being Test Infected to practicing TDD. I was Test Infected several years before I practiced TDD.I was also about as skeptical that moving to TDD from being Test Infected was useful. I was wrong. History tends to repeat itself, so I’m guessing, based on my initial resistance, that this is the future.
Embrace it.
!define TEST_SYSTEM {fit:A} part II 21
In 11/2008 I wrote the first part of this article but I really did not give the background on why I originally asked Bob to add this feature.
So why does FitNesse need to be able to run different parts of suites in different VM’s?
Imagine you are testing services registered on an ESB. That ESB allows deployment of services as EJB’s. There’s something important about that fact. By default, different EJB’s run with their own class loader. You can dig into the EJB spec if you’d like, but there’s roughly a hierarchy of 5 class loaders by the time you get to an executing EJB (can be more, could be less).
Why is this important? If two EJB’s make reference to the “same” JAR file, then each could get loaded by the same or a different class loader. If the JAR file is installed high in the class-loader hierarchy, then they will be loaded by the same class loader instance and therefore will be the same classes.
However, let’s assume that each EJB represents ones service. Furthermore, each EJB makes a reference to some JAR file directly, that is, it is not visible to a hierarchically higher class loader. Then that same JAR file will get loaded twice, once by each class loader (this really happens), and those exact same classes will be considered different.
That’s right, the exact same JAR file loaded by 2 different class loaders are treated as unrelated classes.
In reality, each deployed EJB is “complete” in that in includes the JAR’s it needs to execute. So the “same” jar – same in terms of file contents – exists twice in the system and is loaded by two class loaders.
Now, it gets a little worse. Those two EJB’s work off a “common” data model. Common in that the underlying business objects are common across a set of applications. However, the common data model is a moving target (it’s grown as needed). To manage complexity, not all services are forced to update to the latest version of the common data model at the same time (it’s not really a manageable solution – generally).
So now we have 2 (really several) EJB’s that refer to logically the same JAR but different versions. Luckily, this is no problem because each EJB has its own class loader, so it is OK for 2 EJB’s to refer to different versions of the same logical data model.
How does any of this have anything to do with FitNesse? When FitNesse executes a suite, by default all tests are executed in the same VM with one class loader. So if you have a suite of tests that test different services, each of which might be using a different version of the common data model, then the first service executed loads the common data model, which really isn’t exactly common. This causes tests to fail that would not fail if each text executed with its own class loader.
Rather than deal with writing custom class loaders, Bob instead make it possible to name a VM (see the title for the syntax). By doing this, Bob make it possible to effect a similar environment to that experienced by EJB’s by default.