Ben J. Christensen

Software Development and Other Random Stuff

JUnit Tests as Inner Classes

For several years on multiple Java projects I have written my unit tests as inner classes of the class they are testing. I have never liked or bought into the idea of putting unit tests in a separate class in a separate source folder. I am fine with and like having functional and/or system tests off in that separate ./test/ source folder – just not the unit tests.

Following are my reasons why I find it so much more productive and beneficial to write the unit tests as inner classes.

Note on terminology: I will use “concrete class” to represent the class that needs to be tested.

Low Friction

Unit testing should not feel like a burden, if it does many will likely not do it. Sure, developers often agree on the surface that writing unit tests is “the right thing to do”, but in practice most developers don’t do it. There are many reasons, but I believe one of them is that the friction for doing it is too high in most cases. Partly this is because unit tests off in another source folder have no context to the concrete class being worked on and rely upon human memory and tedious process to find, manage and keep in sync with the concrete class through the development cycle – especially when it’s someone other than the original developer of the class and tests.

Putting the unit tests in an inner class greatly reduces the friction of writing and maintaining unit tests for the following reasons:

  • I only have to deal with a single class in my file/package/class navigator instead of two
  • I don’t have to open and manage 2 editor windows/tabs for every class I want to edit (this is a big deal, especially when most developers have dozens of classes open at any given time)
  • When I use keyboard shortcuts to open that single class file, the unit tests are right there with them, I don’t have to do twice the work to open first the concrete file, then the second file
  • I don’t have to try and maintain the naming convention of 2 separate files, especially through refactorings (more on this below)
  • I can immediately execute the unit tests for the class I’m viewing without going off and searching for another class
  • All developers see the unit tests when they open the class, they don’t need to remember to go looking if there happens to be one (especially in code bases where most classes don’t have tests so they will almost certainly never bother to go looking after failing to find any the first several times).
  • Maintainability is improved because the non-original developers who open a class see the tests and are thereby reminded and encouraged to use and add to them as they edit the class

In short, unit tests as inner classes are easy to find, run, work on and maintain. This in turn encourages adoption and maintenance of them.

Context

Another benefit is that the unit tests as an inner class are very contextual to what they are testing. Many of the points of the previous section related to “low friction” are due to the context an inner class has with the concrete class. The tests are “in your face” and can’t be missed. They are obviously intended for testing the class currently being viewed and immediately prompt the developer to use them as part of their development process.

This in turn enforces them being “unit tests” and not becoming system tests by developers starting to test multiple concrete classes from a single test class just because it’s easier to keep adding tests to an existing test class than to create a new test class for every concrete class. Tests in a separate source folder have a very loose relationship to the concrete class, thus it’s very easy for the context to be lost and have it start testing interaction between classes, rather than only unit testing the class it was originally intended to test.

The mental model of unit tests in an inner class is very clear – these tests are for this class and only this class.

Encapsulation

Unit testing should not result in the weakening of encapsulation. This easily starts to happen when the tests are in a separate class and trying to gain full access to a non-trivial concrete class to setup mocks and perform assertions.

Methods and constructors start being made public or package accessible that should have remained private just so that hooks can be provided for the test class.

Arguments are plentiful about whether private methods and inner classes should be unit tested, and in many cases the arguments are valid that only public methods should need to be tested and they will internally exercise the private members.

Unfortunately there are plenty of use cases I have come across where this ideal is not a reality on non-trivial classes due to a desire to keep things encapsulate and hide implementation details.

Here are 2 examples:

  • Example of ‘wanting’ to test privates: lots of internal logic in private methods where building the class via test-driven-development (TDD) is easier by testing the private methods as you go (like building blocks with simple progressive tests), rather than trying to write all the code then test only the public methods at the end. (Yes, it can theoretically all be done via TDD by only going via the public method, and yes I understand the theory of it. In practice however I have found it beneficial to have some types of private methods tested so they are covered as “building blocks” rather than relying on the top level public method test failing and digging into what internal private method failed.)
  • Example of ‘needing’ to test privates: an inner class which runs a daemon thread to perform background cache refreshes. This is something I want fully encapsulated and not exposed in any way, but I need to test that it correctly runs, does what it’s supposed to do and mock it out for other unit tests.

Specifically on the second example of an inner class and background thread, these could easily be made testable by an external class by exposing things via publics or package private methods or variables, or even by pulling the inner class for the thread into a separate class – but all of those break the encapsulation I was striving for. I do not want the package structure or javadocs to know anything about the implementation details. I want it all private, not package private and certainly not public.

Thus, the only way to get access without breaking encapsulation and good object design is to put the tests inside the concrete class.

Unit tests as inner classes allow for testing without opening member variables or methods to package or public access which then leak the implementation details.

Refactoring

If and when the the concrete class has its name or package refactored the unit tests as an inner class just go along for the ride.

No one needs to remember to go find the associated unit tests and also rename them.

This is particularly important in large codebases maintained by many developers where the person working on the code likely is not the one who originally wrote it.

Otherwise, the unit tests becomes an orphan, in the wrong package with the wrong name. Yes, the tests likely will still work (unless they depend on package access, in which case a compilation error would have flagged it) but they are now less maintainable than ever since the naming convention that was holding them together is gone and nobody will know to go looking for it in future edits to the concrete class.

In short, when unit tests are done as an inner class, everything is fully contained and goes along for the ride regardless of where the concrete class goes or how it’s named.

Self-documenting

When a class has all of its tests as an inner class they act as built-in documentation of what the class is supposed to do, regardless of whether the person looking for the code knows or cares to go looking for unit tests.

They can’t be missed – they are staring the developer in the face at the bottom of the class and in the outline as “UnitTest” with a bunch of methods declaring the functionality that is expected.

Arguments Against This Approach

Unfortunately the use of inner classes for unit testing is not more common so I sometimes get opposition when I work with new teams and they see my tests as inner classes.

Here are the common questions/concerns and my perspective on them:

What About Shipping Test Code to Production?

The small amount of byte code that will get shipped is negligible compared to the amount of 3rd party JARs in most deployments so it hardly dents the size of WAR files being shipped around, and since the classes are never referenced or invoked in production they are never loaded into the class loaders and thus never take up permgen space on the heap.

And if there is a philosophical or actual real reason to not ship test code they can simply be stripped by a build process since they all compile to $UnitTest.class (if that naming convention is used, which I follow and recommend) and can then be easily filtered before building the JAR files.

Apache Doesn’t Do It This Way

Or otherwise said: ‘Why would you put test classes there!?’.

Apache/Maven advocates having a ./src/main and ./src/test folder and they have enough clout in the industry to have made it the most known place of putting test classes.

Just because it works for them doesn’t mean it’s the best way of doing it and in practice I have found it to be detrimental. I agree that in a theoretical “standard directory layout” it makes sense, but in practice the lack of context, increased friction, maintainability issues and impacts on encapsulation make it less-than-ideal for the developers writing the tests.

Summary

Inner classes are a great home for unit tests when writing Java.

This pattern reduces friction of both writing and maintaining unit tests which in turn increases code coverage, speeds up development, improves maintainability, increases velocity and enables adopting practices such as continuous deployment.

 

Update (Jan 17 2012):

One drawback of unit tests as inner classes is that they show up in Javadocs. The solution is to filter them out using a custom ‘Doclet’ implementation.

Example can be found here: https://gist.github.com/1410681

Filed under: Code, Tools

Automount AFP via autofs in Mac OSX (Snow Leopard)

I wanted a mount point that was automatic from my desktop to laptop and didn’t need me to manually re-connect each time I came back to it.

After a bit of research, trial and error I figured out the correct incantation:

Edit the /etc/fstab (create if not there) to be:

HOSTNAME:MOUNTPOINT /PATH_ON_MACHINE_TO_USE_AS_MOUNT url automounted,url==afp://USERNAME:PASSWORD@HOSTNAME/MOUNTPOINT 0 0

Note that “MOUNTPOINT” on Mac for a users directory is NOT “/Users/username”, it is just “username”.

To restart the automounter type:

automount -vc

It will mount the newly defined mountpoint and create the folder defined with PATH_ON_MACHINE_TO_USE_AS_MOUNT.

Some links I found useful while researching:

http://forums.plexapp.com/index.php/topic/14201-howto-automount-afpsmb-shares-using-autofs/
http://rajeev.name/2007/11/23/autofs-goodness-in-apples-leopard-105-part-ii/

Filed under: Tools

Dynamic Directory of Jar Files in Classpath via Eclipse Plugin

I came across a scenario where I needed Eclipse to dynamically add a folder of jar files to the classpath and found out that Eclipse doesn’t support this out of the box (no idea why … IntelliJ does).

So I began Googling and found “how” to solve it by writing a classpath container but could find a pre-packaged solution.

The how was explained here: https://www.ibm.com/developerworks/opensource/tutorials/os-eclipse-classpath/

I took that example and tweaked it into a working plugin. It now lives at GitHub where the plugin and source can be downloaded.

Once the plugin is installed in Eclipse, edit the “Java Build Path” on a project and click “Add Library” and choose “Directory Container”:

Then choose the folder (a subfolder of the project so it’s relative) and defines what file extensions it should include:

Once saved this library will show up like any other Eclipse classpath library and show all Jar files from the selected folder … and most importantly will dynamically update the classpath when refreshed to whatever is in that folder.

I hope this helps someone else needing the same behavior in Eclipse!

Filed under: Code, Tools

Useless SVN Error Message: Network connection closed unexpectedly

If you’re trying to do a subversion checkout using svn+ssh like this:


svn co svn+ssh://hostname/path

… and are getting a useless error like this …

svn: To better debug SSH connection problems, remove the -q option from 'ssh' in the [tunnels] section of your Subversion configuration file.
svn: Network connection closed unexpectedly

Try removing .ssh/known_hosts (which fixed my issue) or ensure that the private/public keys in .ssh have the right permissions, such as this:

benjchristensen-notebook:~ benjchristensen$ ls -al .ssh/
drwx------ 6 benjchristensen staff 204 Jun 1 09:30 .
drwxrwxrwx+ 39 benjchristensen staff 1326 Jun 1 09:24 ..
-rw------- 1 benjchristensen staff 1743 Jun 1 09:17 id_rsa
-rw-r--r-- 1 benjchristensen staff 423 Jun 1 09:17 id_rsa.pub
-rw-r--r-- 1 benjchristensen staff 413 Jun 1 09:30 known_hosts

Filed under: Tools

Ideal Equipment

The following is my opinion of ideal equipment for developing – and anything else I do.

Picture 6

MacBook Pro 15-inch: 2.8GHz

8GB Memory

7200 RPM 500GB Drive

Picture 7

LED Cinema Display (24″)

Because one display is never enough.

Filed under: Tools

Impact of Tools on Productivity

Yesterday I was analyzing java heap dumps at my office using a Mac Pro with 8 Xeon CPU cores and 16GB of memory.

It took 30-60 seconds to load a 3.5GB file and was very usable while browsing the heap and analyzing it.

When I got home I wanted to peruse it a little more. I just had my laptop, a MacBook Pro with a Core 2 Duo 2.5GHz and 4GB memory.

It took over 20 minutes just to load the file, and the machine was virtually unusable that entire time. Once loaded, every click of the mouse took time ranging from a noticeable lag to multiple seconds of being hung. The machine was swapping to death. Even though I have a very high end laptop, it just couldn’t handle what I was throwing at it as compared to the very powerful desktop machine.

I gave up rather quickly as the friction of using the system was too high. I didn’t have the patience to deal with it – I just waited until I returned to the office today and again used the Mac Pro.

It has made me think again about what kind of equipment is provided to development teams. I know for a fact that my extended team of 40+ overseas don’t have a single machine in their office as powerful as the Mac Pro I was using.

So, if one of them needed to analyze that heap dump, profile a large server application or do some other intensive task, what would they do? Deal with 20 minute waits as opposed to 30 seconds, and multi-second pauses between each mouse click – and waste a day in their effort instead of minutes or hours of effective work allowing their tools to work as fast as their thoughts?

One could argue that a remote server, such as one at EC2 could be used for a couple hours by using a web based solution like JHat to analyze the heap. Except that didn’t work so well.

How much productivity is lost because a developer is given equipment below actual requirements, or by making them use the same machine long past its usefulness (3 years is an eternity for a developer, yet is a standard ‘depreciation’ time for which a developer is often made to endure their machine).

For example, I have 4GB on my laptop and push on that limit constantly. Yet I know a lot of my team only has 2GB, and are working on CPU architectures several years old.

For a US developer this is just silly – as having new equipment every 18-24 months is a fraction of the cost of the persons salary, and in my opinion more than makes up for itself in improved productivity as well as morale.

For an offshore developer, with much lower salary costs it’s a higher fraction, but still I believe its dividends are worth it.

This applies to all types of tools and equipment for developers: faster machines, more memory, dual large monitors, commercial software as opposed to everything being opensource and other such things.

People are expensive. I think it’s more cost effective to spend a little on the right equipment and increase productivity and morale of development teams by giving them the right tools – as I had while analyzing heap dumps.

Filed under: Tools

Netbeans Heap Profiler Works. Well.

Netbeans (which I never use) has seemingly come a long way since I last looked at it. The UI is certainly a lot nicer.

Today however, it’s the Heap Profiler that I’m happy with – cause it actually works unlike anything else I’ve tried today.

It loaded a 3.5GB  heap in less than 30 seconds! (I had set my max heap for Netbeans to 12GB on my 16GB, 8-core machine).

Finally a tool for heap analysis that works and works well. And it’s elegant looking at the same time.

Netbeans Heap Profiler

Filed under: Production Problems, Tools

Memory Analyzer Can’t Handle Large Heaps

Despite the claims that Memory Analyzer works well with large heaps, the following screenshot is the evidence of my continued inability to have it parse a 3.5GB heap dump.

I have attempted JDK 5 and JDK 6, both 64-bit, with up to 14GB of memory allocated on an 8-core machine with 16GB of memory.

Note the memory bar at the bottom showing it’s using only 2121M out of 11879M – yet it still thinks it’s running out of memory.

The settings are:

-vmargs

-Xms12g

-Xmx14g

-XX:MaxPermSize=1G

-Dorg.eclipse.swt.internal.carbon.smallFonts

-XstartOnFirstThread

 

-vmargs
-Xms12g
-Xmx14g
-XX:MaxPermSize=1G
-Dorg.eclipse.swt.internal.carbon.smallFonts
-XstartOnFirstThread

 

Memory Analyzer OutOfMemory

Filed under: Production Problems, Tools

Micro-Blogging with Twitter

I started using Twitter about 2 weeks ago. Before that I thought Twitter was a silly thing. Why would I want to post “what I’m doing” at any given moment?

However, a handful of people whose blogs I follow began migrating more and more of their commentary to Twitter. In fact, one of them retired from blogging and only uses Twitter now. Thus, I started an account so I could follow these few people.

I soon came to recognize Twitter for what it can actually be used for – micro-blogging. It’s not just “status updates” as used by teens, tweens and soccer moms – but a viable communication platform for short thoughts and messages that would often go un-written, un-shared, un-communicated (pardon the poor grammar) because traditional blogging (if a 5 year old concept can be considered traditional) needs more content than a single sentence to be bothered with.

To post a blog entry it needs at least a title plus a paragraph.

With Twitter, you just need the title.

Thus, the sharing of thoughts, ideas, quotes, links etc all become more natural because there is less friction in doing so.

As I commented in an earlier post on “Speed of Thought“, if something has friction, it it less likely to be used or performed. The same with sharing of thoughts and ideas.

Blogging reduced the friction greatly from the techniques before it, and Twitter (or micro-blogging more generically) appears to be doing the same for a realm of communication previously not very feasible to attempt.

I have posted 83 messages in 18 days since starting – some benign, others more thoughtful. A mixture of personal and professional.

I do not see Twitter as a replacement of blogs. I see them as very compatible mediums that mix together to create a stream of thoughts and ideas – to be shared and create dialog. In fact, I have mixed them now on this blog as shown by the Twitter feed in the right column, providing a single place to find my thoughts – both those well thought out and edited as blog entries, and those more “sound bite” sized from Twitter.

Despite my views on the subject just 3 weeks ago, I now think Twitter is a valuable addition to our communication toolset alongside email, RSS and blogs.

If you’re still questioning the significance of Twitter and think it’s just celebrities, teens and tweens, check out some of the following which are a few I follow:

The fact that companies, news agencies and governments are using the medium for instant communication – not just personal friends – is an amazing convergence of parties making the medium that much more powerful and useful.

Communicating and staying in touch with so many diverse parties has never had as little friction as this.

Filed under: Personal, Tools

Eclipse Galileo (3.5) and Subversion

Eclipse still does not ship with subversion support by default.

Here’s how I enabled it. Much easier than with Ganymede, but I still shouldn’t have to do this considering Subversion is used by 57.5% of the Eclipse users who responded to the recent survey.

See page 3 of http://www.eclipse.org/org/press-release/Eclipse_Survey_2009_final.pdf:

Subversion is the dominant Source Code Management system used by developers, with 57.5%.”

Anyways, the following screenshots show how to install it from “Help -> Install New Software”.

  • The first site “Galileo” is already included in Eclipse 3.5.
  • The second site is the following URL: http://www.polarion.org/projects/subversive/download/eclipse/2.0/update-site/

Picture 4

Picture 3

Filed under: Tools

Twitter Updates

View Ben Christensen's profile on LinkedIn
Follow

Get every new post delivered to your Inbox.