The latest entry on Otaku, Cedric's weblog mentions JUnit and his woes with running them the way he wants (ie subsets of his suites).
We've run into this problem too and here is what we do : our tests are not organized in explicit suites at all. We use a common practice which is to organize the tests in a parallel structure to the classes they test. Then we can use
For development, we have setup Eclipse to be able to run our tests : sometimes we need to tweak the classpath because we have a hierarchical classpath for our tests but it works really well. What does this buy us : we can run tests on classes, packages or even individual methods which is a real boon !
Otherwise, perhaps Artima's SuiteRunner can help ?
Laurent's latest Incipient.oO{} entry really hit home when I read it. He mentions how the QA team he is helping has been writing tests that work in their own environment but not on someone else's or worse, on the official QA box !
Just last week, I started working on someone else's code. He's an emacs/scriptlet-in-JSPs-crazy/make kind of developer and he's not really up to par on all the latest Java stuff such as unit-testing or the rest.
However, he's really good (and a friend...) so little by little I've been teaching him new things like writing tests, using ANT, continuous integration... I haven't gotten him to use Eclipse yet but I'm sure he'll come to it in time.
Anyway... I first ran the tests he wrote and bam... everything went red...
I had my moment of doubt... after all, the code I was working on was from a merge from a branch he was working on so maybe we had screwed up in the merge process.
But no... looking at the logs I figured out that some of the classes he was using were writing to the disk in a diretory that depended on the value of a property in a config file. I had convinced him to use a config file that was in the testsuite directory so we could "control" what was going on but that wasn't enough : I didn't have a /tmp/export directory and so it didn't work.
My feeling on this was two-fold. First, I shouldn't have to do any setup in my environment for individual tests to work so this was improper : building & testing should be seemless on our QA box (we do continuous integration using AntHill) and it wasn't here. My second thought was that his tests weren't "unit" enough so he'd had trouble getting it to work without just relying on a special setup (his tests basically setup the database, ran a process and checked the result).
So it was time for some anonymous innerclasses magic (the old trick where you overload a method so it does nothing, for example : saveToDisk() ) and refactoring. Incidently, I think the code is much better now; it's now much easier to really unit test the classes.
I've been hit by a nagging OutOfMemoryException
It happens in our "export" function where we scan the contents of a catalog and export data associated with its contents to XML files.
Each object that gets exported has a certain number of attached objects (parent/child relationship). What happens is that we scan each node of the catalog for parents and load the children and their associated data. Then we write that block to the file and forget about it (we even set the reference to null).
However, we need to remember each parent we saved so it gets saved only once even if it's in multiple nodes so we had a collection of integers which were the parents' ids that was used throughout the export process. We usually export a couple hundred or thousand parents.
We added an additional check on the children that get exported. So the collection was changed from a set to a Map. This map is indexed by the parent's ids and its value is a collection of integers which are the children's ids.
When we did this, the JVM crashed with an OutOfMemoryError, even when launching it with 512Mb of memory. It also seemed to be unable to fully garbage collect the memory on the server : everytime it peaked it didn't go back down to where it started (illogical since that map is not that huge and we don't keep all the parent/child data in memory...).
It turns out that the collection of child Ids is obtained from a method which is called on the parent object. This method calls the keySet() method on a map attribute which contained all the children.
When I changed this from a direct return of the keySet to generating a new set of Ids from the ids in the keySet() we no longer had the OutOfMemoryException. (ie doing something like result.add(new Integer(currentKeySetInteger().intValue()); inside an iterator loop). And the garbage collection implementation was able to reclaim all the memory every time it peaked to the max memory assigne to the JVM.
What we know is that the Integer instances used to index the child instances in the map attribute of the parent are being used in an object that stays the lenght of the export. So probably the child instance associated with them are not being garbage collected... but why ?
As I write this I am thinking that this is probably because the map index is actually the reference to the id attribute of the child object so the garbage collector really cannot reclaim it... tricky !! Humm... well, I just checked the code and no... that's not it : the id of the child is actually stored as a primitive int
So I'm stumped but it's a good lesson on garbage collection of how your JVM may starve off its memory if you're careless!
I read Cédric's latest blog entries which mention Aspectwerkz. I was able to very quickly peruse the documentation today and I think it's the first time I have a clear and concise idea of what AOP could buy me without going down XML-config hell and having too much code to write. Even more so, contrary to what I wrote in my very first entry here (basically that I figured it was to difficult to introduce to programming teams) I believe that this could in fact be used in real life, real soon.
I think the reason is that you actually don't need the whole development team to understand it from outset to get it to work (quite unlike introducing a new technology like EJBs or Hibernate or others where everyone must get up to par at the same time).
Not everyone will be writing aspects as a daily activity and aspects are... well... things that are disjoint from the actual business logic so you don't everyone working on them all the time. You can probably get your few "cutting-edge" developers to work on it and let the word spread in the team...
I can really see the Logging advice being useful for us because the legacy app I am working on is sometimes deficient in that area. I can also see security being enforced throughout an application be done using this, even outside of the EJB framework.
My final question is : how dangerous would it be to run our weblogic production servers with Aspectwerkz once it finalizes ? Would it even be possible given the way apps are deployed in the server... I'll have to investigate.
I could have called this "the dangers of IDEs" or "brainless programming" or "write tests before you start changing code"... anyway, you get the picture...
Eclipse has a nice feature which tells you when a local variable is never read after it's been initialized. The thing is... I mistook that for meaning "the variable is useless" so I sometimes removed the line where this variable was set...
Yeah... well, what if your method changes state somewhere... you've basically messed up your code... great !
sigh...
Edit (later on...) : Everbody chill out... I never meant to say it was Eclipse's or the IDE's fault. Actually, I take full blame for making that mistake. I mentionned Eclipse because that's the IDE I'm using.
I was just sharing that mistake with the rest of the community... surely I will not be the only one making it !