junit suite wide setup (not @BeforeClass)

Problem

How do I run setup/teardown for my whole suite, not just one class/test?

Impact of Problem

JUnit offers @Before to run a method before each test and @BeforeClass to run a method once before a class.  For a small suite, @BeforeClass may be enough.  For a large integration test suite, setting up the database is a common task that should be done once for scores of tests.  Having everything in one class is not optimal.  Nor is manually listing all the tests.

Requirements

  1. Continue being able to use ClasspathSuite to gather tests in a subdirectory at runtime.
  2. Run a method before the first of these tests is run
  3. Run a method after the last of these tests is run
  4. Take advantage of JUnit’s runner for running all the tests

Solution

package com.javaranch.test.functional;

import static org.junit.extensions.cpsuite.SuiteType.*;

import org.junit.extensions.cpsuite.*;
import org.junit.extensions.cpsuite.ClasspathSuite.*;
import org.junit.runner.*;

// use cpsuite to dynamically list out tests
@RunWith(ClasspathSuite.class)
@ClassnameFilters( { "com.javaranch.*test.*Test", "net.jforum.*test.*Test" })
// include in case have a parameterized test case
@SuiteTypes( { RUN_WITH_CLASSES, TEST_CLASSES, JUNIT38_TEST_CLASSES })
public class All_JForum_Functional_Tests {
public static void main(String[] args) throws Exception {
setUp();
JUnitCore.main("com.javaranch.test.functional.All_JForum_Functional_Tests");
tearDown();
}

private static void setUp() {
// create the database
}

private static void tearDown() {
// destroy the database
}
}

If you’ve been reading my blog, you’ll know I am doing this to integration test the back end of JavaRanch’s JForum install.  I started by cloning a database and have now moved on to the integration test framework.  Next I will describe the actual database setup.

Refactoring JUnit 3.8 to 4.0 when hierarchy extends TestCase

Problem:

I want to start writing tests in JUnit 4.0, but I have a lot of tests in JUnit 3.8.  I can’t just start writing tests in 4.0, because I rely on common setup/assertions in my custom superclass which extends TestCase. (Which means JUnit will only look for 3.8 style tests)

Solution:

Create one or more new classes to contain static method equivalents that you need.  The new code can use static imports to get these methods.  The original abstract class can delegate to them.

Limitations:

Some frameworks require you extend a certain class.  Until the framework provides a non-JUnit 3.8 dependency, there’s not much you can do here.  You can still use this approach for tests that don’t require that special framework.

UML for refactoring:

Sample code:

package com.javaranch.asserts;

import static com.javaranch.asserts.JavaRanchTestUtil.*;
import junit.framework.*;

public abstract class AbstractJavaRanchTestCase extends TestCase {
   @Override
   public void setUp() throws Exception {
      super.setUp();
      setUp_propertyConfiguration();
   }
}

Conclusion:

I’ve done this refactoring enough times that is second nature by now.  This blog post documents the refactoring since I’m not finding it on the web.

What other problems/sticky situations have you encountered when mixing JUnit 3.8 and 4.0 code?

Plugging Video & Image Memory Leaks in Adobe Air

Adobe AIR is known for memory leak issues, especially in regards to loading and unloading video. I have seen applications with alternating video and images crash unexpectedly after running for only 20 minutes with no user input. After doing some investigating on my own, I can confirm what others have said in the past: You have to take extra steps when unloading a video or image, or risk a serious memory leak.

Removing Images: Clear the “source” attribute
Let’s say you want to unload a set of images from display object myContainer. The obvious solution would be to myContainer.removeAllChildren(), but unfortunately, this is not enough to recover the memory for the images. To truly recover the memory, you need to call:

for each (var child:DisplayObject in myContainer.getChildren()) {
   if(child is Image) {
      (child as Image).source = "";
   }
}
myContainer.removeAllChildren();

My thanks to Russell Brown for this non-trivial solution. I can confirm his results; implementing this solution significantly reduces memory leakage.

Removing Movies: Close the movie
Next, let’s say you want to unload a movie. Most people would just stop the video and remove it from the screen but like the issue with images, this is not enough. Developers should use the following code to properly unload a movie and recover the memory:

for each (var child:DisplayObject in myContainer.getChildren()) {
   if(child is VideoDisplay) {
      (child as VideoDisplay).stop();
      (child as VideoDisplay).close();
      (child as VideoDisplay).source = "";
   }
}
myContainer.removeAllChildren();

Granted, this code assumes you may have multiple movies in your container, although it can be combined with the previous solution to remove images and movies at the same time. Thanks to Ryan Phelan for their groundwork discovering this issue.

Adobe’s Broken Garbage Collector
For whatever reason, simply removing an image or video from the scene and setting references of it to be null is not enough for the garbage collector to recover the memory. If you have an application that cycles through two movies, for example, you may see the memory continue to grow drastically over time as all the previous copies of the video are kept in memory. Hopefully, Adobe will resolve this in future versions of the AIR runtime, but in the meantime developers must take extra steps to sure items have been unloaded and memory reclaimed.