Symphonious

Living in a state of accord.

Why Are My JUnit Tests Running So Slow?

This is mostly a note to myself, but often when I setup a new Linux install, I find that JUnit tests run significantly slower than usual. The CPU is nearly entirely idle and there’s almost no IO-wait making it hard to work out what’s going on.

The problem is that JUnit (or something in our tests or test runner) is doing a DNS lookup on the machine’s hostname. That lookup should be really fast, but if you’re connected to a VPN it may search the remote DNS server which takes time and makes the tests take much longer than they should.

The solution is to make sure your hostname is in /etc/hosts pointing to 127.0.0.1 (and that /etc/hosts is searched first but it usually is). Then the lookup is lightning fast and the tests start maxing out the CPU like they should.

Uglify/Uglify2, Rickshaw, Requirejs and Minification

If you have:

  • A javascript project using require.js
  • Which is optimised using r.js
  • Includes Rickshaw or any other library that uses the prototype class system

Then you are very likely here because you’re trying to enable JavaScript optimization (minification) and finding that suddenly stuff breaks.

The problem is that the prototype class system allows overriding methods to call the original method by adding a $super as the first parameter to the function. From the prototype docs:

When you override a method in a subclass, but still want to be able to call the original method, you will need a reference to it. You can obtain that reference by defining those methods with an extra argument in the front: $super. Prototype will detect this and make the overridden method available to you through that argument. But to the outside world, the Pirate#say method still expects a single argument. Keep this in mind.

The problem is, the first parameter has to be called $super but enabling optimization causes it to be renamed to something shorter, thus breaking prototype’s class system.

The solution, which is easy to find on the internet is to exclude the $super parameter from renaming. What’s not as obvious to find is the exact way to do that since it depends on which optimization engine you’re using.

For uglify, you’re build.js should look a bit like:

({
  ...
  optimize: 'uglify',
  uglify: {
    except: ["$super"]
  },
  ...
})

 For uglify2, you’ll want:

({
  ...
  optimize: 'uglify2',
  uglify2: {
    mangle: {
      except: ["$super"]
    }
  },
  ...
})

 I’d highly recommend using uglify2 and then also enabling source maps with:

({
  ...
  generateSourceMaps: true,
  preserveLicenseComments: false,
  optimize: 'uglify2',
  uglify2: {
    mangle: {
      except: ["$super"]
    }
  }
  ...
})

The key part of getting configuration working for the optimizer is to get the magical nesting level right – lots of places point you towards the “except” config you need, but most put it in the wrong place so it has no effect.