Sunday, September 30, 2007

Spring TestContext Framework

I'm somewhat surprised that there hasn't been more noise around in the blogosphere about Spring 2.1's TestContext Framework. I had the pleasure of working with Juergen Hoeller for a day after JavaZone. Among other things, I learned about the fancy @Autowired annotation that you can use to make your autowiring much safer. Normally autowiring is considered bad practice, but it was Juergen's advice that now it is okay to use. This means in practice that all your service beans will still be declared in an applicationContext.xml file, but the dependencies and object graphs will be annotated in the Java files (or atleast where you see fit).

After this I had a deeper look into the features of Spring 2.1. Note the point about "our next-generation Spring TestContext Framework with support for JUnit4". Now this is cool.

Why we need it (or something like it)

For a long while I (and many of my colleagues and peers) have been annoyed by the disability to manage tests as the amount grows. There hasn't been any good framework around for doing any kind of categorization of tests. Each project would have to invent their own set of hacks in order to control their test suites, be it a TestFactory picking up system variables, or using different Maven profiles and source folders for different categories of tests. In short, inventing some sort of convention for seperating tests: put them in different folders, use name conventions like *Test.java, and *IntegrationTest.java.

Have you ever been in a project where you and your team dropped automated testing because you couldn't manage the mass of tests? Well, tools are starting to appear now that can save your hiney.

TestNG solves this. Why don't you just use that?
The first solution that many have become aware of is TestNG. I really like the feauteres, but as of Alex presentation on JavaZone, Maven's surefire plugin still has issues running TestNG. Also, Eclipse (our standard IDE) has built in support for JUnit4. And finally, Spring comes with a bunch of lovely standard testbase classes that make your integration tests nicer. Oh, wait. You don't want your test to inherit from a Spring class? Read on to find out. Final reason: everyone knows JUnit and not too many know TestNG (sorry Alex..).

There's a new kid in town
Spring TestContext Framework introduces a wide range of new annotations for doing tests, my absolute favourite being the @IfProfileValue that you can use to specify testing environment (in other words implement the test categorization I spoke of above). There is only one implemented ProfileValueSource (being the logic that decides which profile it is) that checks for system variables, but it is easy to extend with your own ProfileValueSource class that contains the logic for deciding which tests to run.

As promised: avoid extending Spring's testbase classes: Use the @RunWith(SpringJUnit4ClassRunner.class annotation instead.

You got the regular nifty annotations like @Repeat (guess what it does) @Timed (fails if the tests exceeds a time limit, different from JUnit 4's timeout attribute), plus a bunch of Spring environment controlling transactions and Spring contexts. You don't need to use the @ExpectedException any more because JUnit4 supplied us with the @Test(expected=RuntimeException.class) functionality. Spring people recommend that you use JUnit's way of doing it.

"Caching between testing", and "injection of test fixtures". Sounds lovely, doesn't it? Sounds alot like the presentation of TestNG, but hey, it's JUnit :)

There is also a pretty cool @ContextConfiguration annotation for declaring which Spring bean XML files you want to use for a particular test.

Actually, instead of me repeating the whole documentation, why don't you take a look for yourself. Note that I haven't actually played around with this properly yet (well, we got as far as getting the M4 build into our maven repository) cause I left my laptop in work. I'm gonna try setting up the machine here tonight and see if I can get something done before bedtime.

By the way, some shameless company promotion: My employer is doing a course on Spring 2 with Interface21 in Oslo in the beginning of November. Per is a really friendly guy, so don't hesitate to give him a call and ask about it if you're curious :)

Sunday, September 16, 2007

Post JavaZone 2007

In other news, this week I attended JavaZone 2007. Here's a wrap-up:

Wednesday

I was going to attend Stephan Janssen's talk on Web 2.5, but unfortunately the room was completely packed when I got there. So I headed over to Johannes' talk. Not surprisingly, his room was stuffed full as well (and appearantly he never got his projector working). So I ended up wandering into Kaare's talk on open source. As always Kaare delivers a quality talk (with cool slides!), but I can't help being slightly disappointed he chose a more exiting and technical subject.

I headed on to catch Craig McClanahan (hey, wasn't that hard to spell) and his talk on jMaki. It's not the first time I've been presented to it, got some of it on Jazoon. jMaki certainly is a platform to be reconed with for JavaScript developers, and I hope it (or something similar) will become a de facto standard for the range of JS-widget libraries appearing today.

Around then I discovered my phone had been constantly been ringing and messaged because I had missed stand-duty on Objectware's stand for about one hour and a half :)

A real eye-opener was James Coplien's talk on the fallacies of Agile. I say eye-opener because, even though I recognize many of his points as common knowledge/sense, we still need to get these points ruffled up again once in a while. He did sink to some low levels in order to get his message through. Actually, he used the exact same tricks of exaggeration, exclamation and statistics as the opposition does (them being agile evangelists). He said "TDD/Agile is fashion", well I have to add that being anti-agile is quite the fashion too these days. I hope his talk (and his mood was shared by many others at the conference) will inspire to more heated, but healthy, discussions at the coming XP- and agile meetups.

I attended Anders NorĂ¥s' great talk on Java DSLs, the interesting 100 KB Kernel talk, Martine Devos estimation talk which didn't really give me anything new. After that I missed a talk because we started handing out beer at our stand :)

Finally, it was Totto's SOA roleplay BOF, and even though it was poorly attended, we got free beer and learned some valuable lessons about software infrastructure, and the industry as a whole. If you didn't understand SOA before this BOF, you certainly got the idea of why the term has appeared and become such a huge area of industry attention.

From there on out there was free beer (unfortunately they "ran out" before I got there).

Thursday

I got up to attend the AOP Java Grid Computing talk, but unfortunately each time the speaker was about to make a point, his insanely americanized but still incomprehensible accent made it impossible for me to keep up. I went to Alex' talk on Test'n'Groove. Definitely a subject I'll look more into.

I went into Matt Raible's comparison of web frameworks. I had already caught the essence of the talk from clicking though the slides earlier on, but still its nice to see Matt on stage. He's a good speaker and I like his pragmatic approach to everything. It's funny, all the really clever developers I know can't stand Matt's whining/opinions/implementations. All the average developers, however, love him because he figures out how stuff works. And that's why he's so popular, I guess. Clever developers like to figure stuff out on their own.

After that it was on to Jacobsen's talk about practices. Same shit, new wrapping, I figure. His "Deck of many practices" is naturally important for project managers who don't know their way around, but for seasoned project managers who have been through the whole RUP and Agile thingie, all these practices should be common knowledge. Nice framework, but we hate frameworks. I prefer to consider them guideline recommendations.

Then I made the stupid mistake of not getting into the how-to-call-a-method-talk (room was too full), instead wandering into an Ajax talk. How dare these guys label their talk with intermediate/advanced? This was frigging JavaScript for beginners. When they tried to explain the concept of manipulating the DOM for the second time after 10 minutes, I left. Loudly.

Then I made an even worse mistake of wandering into Eivind Waaler's Struts 2 talk. Okey, okey, I should've figured out this would be nothing new to me, but I thought "Hey, it's labelled intermediate/advanced as well, so it must be something new". This was an introduction to Struts 2, not a bad one, at that, but it could've contained some strategies on testing interceptor stacks and web integration tests.

Then it was on to the Space Based Architecture by Owen Taylor talk. Now this was JavaZone material! Taylor is by far the best speaker I've seen this year, and the subject of the talk was of course very fitting as we have been playing around with JavaSpaces recently. Maybe you saw the 3D-animation on the big screen inside our stand? That was a distributed ray-tracer image generation application shared between 5 computers (counting 22 CPU cores), sharing the bits of image generation on a JavaSpace!

The bad parts

I'd like to quote Totto (from here):
"We know that the participants need a lot of coffee and mineral water."
There were *two* coffee areas, with two coffee dispensers on each. On thursday morning, the line in front of the coffee was about the same length as before wednesday's lunch (pretty long). There were no water bottles in sight, only tiny plastic cups and jugs filled with water. Look, it's thursday morning, after PartyZone. What I really need is an IV bag filled with soothing water. Bringing a tiny cup into the first lecture ain't gonna cut it :)

Also, be tougher on rating the talks. If the subject is "Introduction to.." , label it green.

Oh, and the chairs! The friggin tiny chairs! I never knew Java programmers were that wide-shouldered. Bad enough that the talks were stuffed, but there was not room for one man on one chair. Keyword squeeze. Nuff said.

Oh, and another thing! If you're a speaker, and you're done with your talk (which you should do on time), don't drag on the time asking for questions if your out of time! Once the clock hits it, say "Thank you" and wait for applause. If there are no questions, say thank you quickly and let the audience applause and leave.

Which brings me onto the audience: Don't leave the room before the friggin talk is done! Even if the speaker has gone past her time, I'm trying to pick up what's being said in the Q&A and your slamming of chairs, feet and doors is giving me a hard time doing exactly that. Don't get up before the talk is done!

The good parts

Well arranged, as always. Good range of quality talks. I enjoyed the topology of the stands and the speaker-rooms. I liked the 360-scene. I like free beer (even though I got very little).

Well, way past my bed-time now. I'm sorry I didn't get to do live blogging during the conference like I did last year and like I did under Jazoon. There's just been too much todo on my hands to be dragging the laptop around with me (not like I would've been able to fit it on my laptop with those tiny chairs). Funny, it just struck me that if you had mixed the good parts from Jazoon with the good from JavaZone, you would've had gotten the perfect conference.

Continous web testing with Selenium, Maven and Continuum part 2

Update: Fixed camelCase in localRepository tag.

It's been a busy week, with JavaZone and some exiting things going on in my project at the same time.

I'll get straight to the point and post an exampe app that will solve the problems from the previous post.

I started off with a maven archetype create webapp.

I added configuration of the Jetty plugin (note that this isn't really necessary to get the rest working, but is handy for testing out the webapp with mvn jetty:run).

I put the web-test running in its own profile, so it won't be ran with each mvn install. This is to underline the fact that you probably don't want the web-tests to be run each time you build the app. Web tests take too much time and should be done by your CI system.

So, all the details of configuring maven for running Selenese tests are inside the with id "web-test". I've done a few other modifications as well, adding a couple of snapshot repos, and the web tests of course. I added a simple little test that verifies that it can find the text "Hello World!" when browsing to localhost:8080/maven-selenium-example.

Download
https://github.com/tfnico/maven-selenium-example

Requirements

  • Firefox 2.0 or later installed
  • Maven 2.0.7 (or thereabouts) installed
  • M2_REPO (environment variable) pointed to a folder without spaces *
* Because of this bug, the path to your maven repo can not contain spaces (as in C:\Documents and Settings\Thomas.Nicolaisen\.m2\repository). So, move your repository to f.ex. c:\m2-repo and change C:\Documents and Settings\[usernemame]\.m2\settings.xml to include:

<settings>
<localRepository>c:\m2-repo</localRepository>
....
</settings>


This will most likely not be necessary on a non-windows system.


Instructions
  1. Unzip
  2. Commando-line into \maven-selenium-example
  3. Type mvn install -Pweb-test
  4. Wait a while for all the dependencies to download
  5. Build successful!
That last maven parameter instructs maven to use the web-test profile.

Be aware that since there are plenty of snapshot dependencies in this configuration, any of them could be upgraded any day and (if the developers have done a poor job) break the web-test configuration. If you want a 100% stable integration test environment you should specify version number on each plugin (especially cargo-maven2-plugin, and change the selenium-maven-plugin to non-snapshot).

Sunday, September 09, 2007

Continous web testing with Selenium, Maven and Continuum

Wow, nearly a month without posting. I haven't really gotten any good excuses, just lack of stuff to write about, I guess. But for the last week I've been struggling and doing something I find really interesting and useful: Web-testing.

Regular readers will know about my love for Selenium. I still believe that Selenium is the way to go about web-testing.

So, the web application in a project was approaching web-test-worthiness quickly (well, actually it was about a month or two past the point where we should've started doing web-testing). Mind that we were already doing continous integration on the project, so it was only for the reason of not having core-developers breaking any of the stuff being out in the web.

Let me clarify a bit on that last point: Modern web frameworks expose core domain objects way out into the web (like the User.lastName property here in Matt Raible's example).

When core developers refactor Java classes - XML files, property files, JSP files and JavaScript files are not brought along in the equation (especially not in Eclipse).

Breakage caused by these changes will most likely not be discovered in your unit tests. You need web-tests.

There are a number of other good reasons for doing web-testing, like the ever increasing amount of JavaScript in your webapp, and testing the web across different browsers. So web-testing is a Good Thing.

I'm not going to go on about the different strategies for getting continous web-testing implemented. The elements I were after were:

1) Getting Maven to test with Selenium scripts (no, not JUnit tests exported from Selenium IDE)

Now normally, this isn't too hard. Alot of projects out there do web-testing by storing Selenium tests as Java-code - JUnit tests. But the trick here is to get Maven run tests based on tests in the Selenese format - pure html tables with web-browser instructions (they look a bit like Fit-tables).

There is an ant-task for doing this, which in later turns has been converted to a Maven plugin goal: Selenium Maven Plugin's selenese goal. It was originally a seperate plugin called Mavenium, but now the project seems to have been absorbed into the other one.

2) Getting Continuum to run these tests.

Once Maven is running the tests properly, it shouldn't be a problem to get Continuum running these. BUT there's the issue of how the web app should be deployed and started for the Selenium plugin to have something to run on. Cargo was the obvious tool for doing this job, but there were some bumps on the road to getting it working.

3) Getting the tests to run headless

As shown here, with the headless option in the selenium plugin. Anyhow, I ended up not using that plugin-goal, instead just starting Xvfb manually on the Linux box and setting the DISPLAY variable to something like 127.0.0.1:1. Then there was a whole bunch of trouble getting Firefox 2.0 in on Fedora Core 6 and so on.. Yech.

I believe these three requirements have not been met together on many other projects, and this combination has not been properly documented anywhere else. This is perhaps because only recently have the plugins involved matured to such a degree that this process is possible at all. I did try achieving the same goals before the summer, but ran into all sorts of problems with Firefox 2.0 instances not being started correctly and problems using the maven-cargo-plugin.

The closest I ever found was this how-to. But still the example uses Selenium's JUnit test (we want HTML-tests, remember?).

So in the next post I'll put together an example that actually does the whole thing my way. I did run into a couple of problems with cargo that I have not been able to solve (ended up hacking the plugins somewhat), but still the example should work on a general basis. Too tired to make it right now though.