Fabrizio Giudici is a Senior Java Architect with a long Java experience in the industrial field. He runs Tidalwave, his own consultancy company, and has contributed to Java success stories in a number of fields, including Formula One. Fabrizio often appears as a speaker at international Java conferences such as JavaOne and Devoxx and is member of JUG Milano and the NetBeans Dream Team. Fabrizio is a DZone MVB and is not an employee of DZone and has posted 67 posts at DZone. You can read more from them at their website. View Full User Profile

JUnit: A Little Beyond @Test, @Before, @After

08.26.2009
| 26651 views |
  • submit to reddit
Most people I see using JUnit are limiting themselves to the very basic features, that is, indicating tests with @Test and maybe @Before and @After. Hey, I myself didn't do much more than that up to a couple of weeks ago. This is just a syntactical update to Java 5, but later releases of JUnit can do much more.

Consider my jrawio project: it's a decoder for different image file formats, so the integration tests match the same scheme: get a file, read and extract some information from it, assert expected results (as a marginal note for understanding the following examples, to assert that I'm reading the expected raster, which is made by many millions of pixels, I'm computing its MD5 and checking against it).

This is a sketch from a decoder test as it was at the beginning of this month:

public class NEFImageReaderTest   
{
@Test(timeout=60000)
public void testJRW146()
throws Exception
{
final String path = "https://imaging.dev.java.net/nonav/TestSets/fabriziogiudici/Nikon/D100/NEF/NikonCaptureEditor/ccw90.nef";
final ImageReader ir = getImageReader(path);
assertEquals(1, ir.getNumImages(false));
assertEquals(1, ir.getNumThumbnails(0));
assertImage(ir, 3034, 2024);
assertThumbnail(ir, 0, 120, 160);
final BufferedImage image = assertLoadImage(ir, 3034, 2024, 3, 16);
assertLoadThumbnail(ir, 0, 120, 160);
close(ir);

assertRaster(image, path, "3659664029723dc8ea29b09a923fca7d");
}

@Test(timeout=60000)
public void testJRW148()
throws Exception
{
final String path = "https://imaging.dev.java.net/nonav/TestSets/fabriziogiudici/Nikon/D100/TIFF/TIFF-Large.TIF";
final ImageReader ir = getImageReader(path);
assertEquals(1, ir.getNumImages(false));
assertEquals(1, ir.getNumThumbnails(0));
assertImage(ir, 3008, 2000);
assertThumbnail(ir, 0, 160, 120);
final BufferedImage image = assertLoadImage(ir, 3008, 2000, 3, 16);
assertLoadThumbnail(ir, 0, 160, 120);
close(ir);

assertRaster(image, path, "03383e837402452f7dc553422299f057");
}

...
}

Pretty much copy & paste, isn't it? Figure out that I've got dozens of test files, more will be added, and a lot of metadata items must be tested too. This isn't going to scale a lot.

Published at DZone with permission of Fabrizio Giudici, author and DZone MVB.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Tags:

Comments

Guillaume Jeudy replied on Wed, 2009/08/26 - 12:41pm

Fabrizio,

 Have you tried testNG? It has a similar feature and seems easier to use than the example you posted here.

 See @DataProvider annotation. The test runs also display much nicer in eclipse IDE than what you posted in this article. It shows the test method with arguments passed.

 More over it has multi-threaded testing support though I haven't tried @DataProvider option combined with multi-threaded testing.

Anew Hope replied on Wed, 2009/08/26 - 8:43pm

@Fabrizio

One thing to note is that @RunWith is experimental in JUnit. I just checked the latest version of JUnit (4.7) and the javadoc is consistent with the following link:

http://junit.sourceforge.net/javadoc/org/junit/runner/RunWith.html

"...We added this feature late in development. While it seems powerful we expect the runner API to change as we learn how people really use it. Some of the classes that are currently internal will likely be refined and become public."

So I wouldn't rely on this for a large amount of testing. Also, the explanation of how JUnit finds constructors based on the number of arguments doesn't appear to be correct. I think a JUnit expects there to be only one constructor otherwise you'll get a "Testcase: initializationError" at least in JUnit 4 (standard in Netbeans 6.7.1).

I like your modification to Parameterized and hope they accept the changes.

Casper Bang replied on Thu, 2009/08/27 - 6:04am

Hmm, could one not also write a generator extension that hooks in front of JUnit's preprocessor? Then something like this would be possible:

    // @ImagesTest support 
    @interface JUnitGenerator{
        // Marker
    }
    @JUnitGenerator
    @interface ImagesTestGenerator{
        ImageTestParms[] value();
    }

    @interface ImageTestParms{
        String path();
        String md5();
        int w();
        int h();
    }
    
    // Test file
    @ImagesTestGenerator(
    {
        @ImageTestParms(path = "coke.jpg", md5 = "baa62439fb6e5183bd7c7be304dbf45f", w=1080, h=900),
        @ImageTestParms(path = "pepsi.jpg", md5="5e2c9f279cfed2de1260d71ff7b3d9c2", w=1600, h=1200),
        @ImageTestParms(path = "coffee.jpg", md5="efcf7c6bcfad3179c8876a8b184d0551",w=480, h=360)
    })
    public void ImagesTestTemplate(String path, String md5, int w, int h) {
        ImageReader ir = getImageReader(path);
        assertRaster(ir, md5);
        assertWidth(ir, w);
        assertHeight(ir, h);
    }

At compile time, let a simple AnnotationProcessor (recognizing the marker interface JUnitGenerator) generate the @Test methods via TreeTranslator. JUnit will see things as if you handcoded each and every test method.

-------------------------------------- 
All 3 tests passed.(0.066 s)
     ImageTest_coke passed (0.0 s)
     ImageTest_pepsi passed (0.0 s)
     ImageTest_coffee passed (0.0 s) 
-------------------------------------- 

 

I realize code generation is a touchy issue, but I always found it handy for testing (although admitedly  I've never done it exactly like this).

Ignacio Coloma replied on Thu, 2009/08/27 - 3:01am in response to: Anew Hope

@anewhope: the spring testing module relies on @RunWith, so hey better do not remove this in the short term :)

Denes Csepely replied on Fri, 2009/08/28 - 3:59am in response to: Ignacio Coloma

Yeah, Spring does and libs/frameworks provide their runwith classes too. If you need DI you use spring's runwith. If you need DI and want to leverage a runwith of any other framework u can't do that (or i missed something). You cannot specify two or more runwith therefore a workaround solution needed. I think the runwith is not as flexible as it would be.

Fabrizio Giudici replied on Fri, 2009/08/28 - 8:53am in response to: Denes Csepely

@gjeudy: Yes, I know about the existence of TestNG and that it offers more features than JUnit - in a way, one can say the latest JUnit versions are trying to catch up. The problem is that I'm already working with too many new libraries and products... trying to keep a limit at the moment. Probably I'll give it a try later in the year.

@anewhope. Yes, I know this thing is not part of a stable API. But it would not be hard to apply changes after JUnit eventually changes the API.

@casperbang. Very nice suggestion! No, I don't get worried by code generators :-) indeed there are already a couple in jrawio. Your suggestion sounds as a nice alternative to Groovy - indeed this brings me to a recurrent thought, that every time I think Groovy is useful for a problem, I later found (or somebody later suggests) an equivalent way to do things with Java ;-)

Peter Sellars replied on Sun, 2009/10/11 - 2:15am in response to: Fabrizio Giudici

Hi Fabrizio - did you submit a patch for this? Was it accepted or rejected? It seems useful to have a name for reference rather than just an index? Something like this could be an extended Parameterized class - such as IdentifedParamerterizedClass.

 Am curious as I am going to use your patch for an upcoming presentation on this feature of JUnit. Will acknowledge you in my presentation and link to this page. Am also going to look at using a file/or group of files to contain the test data.

john green green replied on Mon, 2009/10/26 - 3:27am

The problem is that I'm already working with too many new libraries nike shoes russia and products... trying to keep a limit at the moment. Probably I'll give it a try later in the year.

Mateo Gomez replied on Tue, 2012/04/17 - 12:28am in response to: Fabrizio Giudici

 hey Farbrizio, great job on this for answering the question back.Thanks!

 mexican dessert recipes

Matt Coleman replied on Fri, 2013/01/11 - 1:06am

great test...i so appreciate the before and after of it

buffalo search engine optimization 

Cata Nic replied on Tue, 2013/09/03 - 3:49am

 This post should be promotted into a better way. I think the solution presented here is easy to understand and should be promoted at large scale.

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.