Something we’ve be trying to pay more attention to with our newest green field development projects is the running time of our unit test suites. One of the projects was running ~200 unit tests in 2 seconds. As development continued and the test case number grew, it started taking 10 seconds, then over 30 seconds. Something wasn’t right.
First challenge was to determine which were the slow running tests. A little googling found this useful patch to the python code base. Since we are using python 2.5 and virtual environments we decided to simply monkey patch it. This makes verbosity level 2 spit out the run time for each test. We then went one step further and made the following code change to _TextTestResult.addSuccess:
def addSuccess(self, test): TestResult.addSuccess(self, test) if self.runTime > 0.1: self.stream.writeln("\nWarning: %s runs slow [%.3fs]" % (self.getDescription(test), self.runTime)) if self.showAll: self.stream.writeln("[%.3fs] ok" % (self.runTime)) elif self.dots: self.stream.write('.')
With it now easy to tell which were our slow tests we set out to make them all fast again. As expected the majority of the cases were an external service not being mocked correctly. Most of these were easily solved. But there were a few tests where we couldn’t find what hadn’t been mocked. Adding a few timing statements within these tests revealed the culprit. The Django frameworks assertRedirects method.
def assertRedirects(self, response, expected_url, status_code=302, target_status_code=200, host=None): """Asserts that a response redirected to a specific URL, and that the redirect URL can be loaded. Note that assertRedirects won't work for external links since it uses TestClient to do a request. """ if hasattr(response, 'redirect_chain'): # The request was a followed redirect self.failUnless(len(response.redirect_chain) > 0, ("Response didn't redirect as expected: Response code was %d" " (expected %d)" % (response.status_code, status_code))) self.assertEqual(response.redirect_chain, status_code, ("Initial response didn't redirect as expected: Response code was %d" " (expected %d)" % (response.redirect_chain, status_code))) url, status_code = response.redirect_chain[-1] self.assertEqual(response.status_code, target_status_code, ("Response didn't redirect as expected: Final Response code was %d" " (expected %d)" % (response.status_code, target_status_code))) else: # Not a followed redirect self.assertEqual(response.status_code, status_code, ("Response didn't redirect as expected: Response code was %d" " (expected %d)" % (response.status_code, status_code))) url = response['Location'] scheme, netloc, path, query, fragment = urlsplit(url) redirect_response = response.client.get(path, QueryDict(query)) # Get the redirection page, using the same client that was used # to obtain the original response. self.assertEqual(redirect_response.status_code, target_status_code, ("Couldn't retrieve redirection page '%s': response code was %d" " (expected %d)") % (path, redirect_response.status_code, target_status_code)) e_scheme, e_netloc, e_path, e_query, e_fragment = urlsplit(expected_url) if not (e_scheme or e_netloc): expected_url = urlunsplit(('http', host or 'testserver', e_path, e_query, e_fragment)) self.assertEqual(url, expected_url, "Response redirected to '%s', expected '%s'" % (url, expected_url))
You’ll notice that if your get request uses the follow=False option you’ll end up at line 34 in this code snippet which will kindly check to make sure the page you are redirecting to returns a 200. Which is great, unless you don’t have the correct mocks for that page setup too. Mocking out the content for a page you aren’t actually testing also didn’t seem quite right. We didn’t care about the other page loading, it had it’s own test cases. We just wanted to make sure the page under test was redirecting to where we expected. Simple solution, write our own assertRedirects method.
def assertRedirectsNoFollow(self, response, expected_url): self.assertEqual(response._headers['location'], ('Location', settings.TESTSERVER + expected_url)) self.assertEqual(response.status_code, 302)
Back to a 2 second unit test run time and all is right with the world again.
A few weeks ago I had an opportunity to go to The Server-Side Java Symposium, an annual event for Java aficionados held in Las Vegas, Nevada. What happened there will not stay there, however.
I found a few interesting things out, and I’m going to try to share them over the course of a few blog posts, in case anyone out there is interested, and so I can find them later for myself as well.
TSSJS is not about vendors, it’s about technical info, so there were only a few “booths” from the handful of commercial sponsors of the event, one of which was, inevitably, Oracle. Given the Sun acquisition, a question on the mind of many developers has been “what’s Oracle going to do for/with/to Java?”.
It’s a legitimate concern, and indeed a complex question with a number of complex answers – but one of my reasons for being in Vegas was to get some of the answers.
The keynote presentation at TSSJS was by James Gosling, the “father” of Java. As everyone no doubt reading this already knows, he’s subsequently left Oracle, for undisclosed reasons. That, to me, lessens the impact of his remarks somewhat, as I suspect he knew by the time we heard him speak in Vegas that he’d be on the way out the door, but he still had a lot of interesting things to say.
About 800 people were in the room, I estimated, to hear the keynote. Interestingly enough, Gosling’s position at Oracle was “Client Software Group” VP. I generally don’t think of Java as having much to do with “client” software, personally, so that in itself was informative.
He had an image of the Java mascot (the little delta-shaped guy) wearing a snorkle in a fish tank, a play on the “Soracle” name mash-up.
In any case, the keynote touched on what’s happening in the Java world. He emphasized the wide spectrum of devices on which Java is found, and how networking ties all of these devices more and more into a cohesive whole.
Some stats were mentioned: there are about 15 million downloads per week of Java, and something like 10 billion (with a “B”) Java-enabled devices of one sort or another out there in the wild, perhaps 1 billion of which are Java-enabled desktops. By any metric, Java is a huge success, and is in many ways more popular in the rest of the world, especially Europe, than it is in North America.
100 million of those devices are are TV devices, and on top of all it are about 2.6 billion Java-enabled cell phones.
Conclusion: It’s not going away, soon or quickly.
A site like the Apple App Store existed for Java apps 7 years before Apple’s app store – but it was in Japan.
There are 5.5 billion smart card devices Java-enabled out there – the V3 standard actually has a servlet container in it – U.S. military dog-tags apparently now use this standard.
The Amazon Kindle is a Java device, under the skin.
Gosling proffered a definition of success: being completely invisible, people just get stuff done.
There are something like 6.5 million professional Java developers out there, 800 thousand of which are in India. Most colleges have a Java course requirement, modifying the old saw of “write once, run anywhere” to include “learn once, work anywhere”.
After this deluge of interesting stats, Gosling moved on to discuss the next big thing in Java, in his opinion: Java EE 6, the foundation for next-generation enterprise software. The spec was approved November 30th, 2009.
There are two major flavors of JEE6 – the “full” profile, with everything, and the “web” profile, with EJB3 “Lite” and just the most frequently used specs, not the more obscure stuff.
A major emphasis in next-generation Java development is modularity: making hard problems easier by breaking them into a number of less-hard problems. Major endorsement here for OSGi.
As far as Gosling’s concerned, the correct amount of XML required is exactly none 🙂 Many developers in the room agreed with him, and it’s now possible with JEE6 and it’s powerful annotations.
Much of the benefit of dependency injection and resolution that Spring provides has been baking into the core Java EE platform now, and much of the pain of EJB has gone away. In fact, one of the most painful parts of EJBs, CMP Entity Beans, is no longer supported by the spec at all, in favor of JPA.
Glassfish V3 is the JEE6 reference implementation, and it’s OSGi-based.
Then it was demo time: Gosling (with some help from a couple of developer types) fired up Netbeans and Glassfish and did some show and tell of the coolness of JEE6.
We saw a webapp deployed – with no web.xml, no WEB-INF directory at all, everything annotation-based and dependency-injected at the proper times. We saw a stateless EJB auto-deployed to via an OSGi bundle into the container in less than a second, direct from the IDE. No boilerplate, no config, no reams of XML files to bolt it all together, just code and go.
We saw that same app preserve session state even when it was redeployed, which was very cool (a counter was showing the number of hits to the page – code was changed and redeployed, and the counter kept incrementing – and no, it wasn’t stored in a client-side cookie, it was in the session).
I noticed that all the Oracle guys were using Macs, incidentally.
Gosling notes that JEE6 shouldn’t just be one version number past JEE5 – it’s more like JEE 60 in comparison 🙂
Saw the @Schedule annotation, where a bean can be scheduled for execution with cron-like ease, but all within a JVM.
Gosling noted that Felix was the web container under the skin of Glassfish.
We saw the @Observes annotation being used – a way to register listeners without any code or configuration. It was noted that Swing could benefit enormously by this pattern.
Then we saw a demonstration of Glassfish’s web console. The “web profile” of JEE6 doesn’t include JMS by default, so the example shown was adding that support by installing a new bundle in the running container. Two clicks and it was done. A GUI admin console can be added for any bundle, including your own bundles.
Gosling then wrapped up with an overview of some of his personal projects, and then took some questions. He also mentioned a new “app store” for Java that’s in the works, to be coming on “store.java.com”. It’s in the final stages of work now, apparently.
That was the end of the first keynote of TSSJS. In the next few posts I’ll talk about some additional sessions that my associate and I attended, and some of the other good stuff we learned.
The final post in a 3-part walkthrough for automatically versioning and provisioning features for OSGi deployments. This post discusses how the features.xml file produced by the previous 2 posts can be told to automatically manage version numbers.
The post begins with an explanation of our motivation, discusses a forked modification to an existing Maven plugin which will provide the functionality we require, and finally move into the use of the plugin in the pom.xml.
This post, like the previous posts, is code-heavy with bare descriptions. Questions are very welcome.
(Follow the link for the full blog post)
This is part 2/3 describing how to set up a pom to provision a features.xml for a ServiceMix Deployment, deploy and release the file to Nexus, and automate the handling of version numbers.
The post begins with the simple setup for localized installation. It then moves on to how to get Maven to deploy the artifact to a Nexus repository properly, before explaining the tweaks needed to release to a different repository.
For the XML-phobic, this post is fairly XML-heavy as most of the concepts are self-explanatory.
(Follow the link for the full blog post)