How to determine the JUnit 4 current test name


In my unit tests I often want to know the name of the test that is executing. For example, I often want to have the golden file (expected test output) computed automatically from the testname. As another example in my JavaFX testing, I often generate screenshots inside failing tests and it's useful to name these screenshots by the failing tests.



In JUnit 3 this was simple, since your testcases would extend a builtin JUnit class which had a method you could call to return the current test. However, with JUnit 4 that's no longer possible. I've googled and found the "correct" way to do it - using a special @RunWith to run the test class - but I find that solution unsatisfying. My utility methods which are invoked to read golden files and screenshot etc are in one place and I now have to decorate all my tests. Besides, I already have a @RunWith annotation on my tests because I want to run them on the event dispatch thread so I have a special test runner for that.



So, I've found a better way to do it. Better for me I mean - this may have problems and limitations I'm not aware of, but for all of my tests this worked wonderfully, and doesn't have the @RunWith requirements (though note that I don't do multithreading in my tests, other than invoke them on the event dispatch thread, so if you try to call this from a thread that didn't invoke the test it probably won't work):


public static String getTestName() {
// Try to find a method on the stack which is annotated with @Test -- if so, that's the one
StackTraceElement[] elements = new Throwable().fillInStackTrace().getStackTrace();
for (int i = 1; i < elements.length; i++) {
StackTraceElement element = elements[i];
try {
Class clz = Class.forName(element.getClassName());
Method method = clz.getMethod(element.getMethodName(), new Class[0]);
for (Annotation annotation : method.getAnnotations()) {
if (annotation.annotationType() == org.junit.Test.class) {
return element.getMethodName();
}
}
} catch (NoSuchMethodException ex) {
} catch (SecurityException ex) {
} catch (ClassNotFoundException classNotFoundException) {
}
}

// Just assuming it's the calling method
return elements[1].getMethodName();
}


As with most of my test utilities, it's a public static method living in a class called TestUtils, which I statically import from my test cases such that I can simply reference the test name getter like I would in the JUnit 3 days:

import static org.junit.Assert.\*;
import static my.package.name.TestUtils.\*;

/\* ... \*/

screenshot(scene, getTestName());


By the way if you're using JavaFX you might be interested in the screenshot utility method. It's really simple:

public static File screenshot(Scene scene, String fileName) throws Exception {
BufferedImage image = (BufferedImage) scene.renderToImage(null);
if (!fileName.endsWith(".png")) {
fileName = fileName + ".png";
}
File file = new File(getScreenshotDir(), fileName);
file.createNewFile();
ImageIO.write(image, "png", file);
return file;
}

(where obviously getScreenshotDir() returns a File folder where you want your screenshots generated. A decent default implementation is return new File(System.getProperty("java.io.tmpdir")); ...)

Comments:

Sadly this did not work for my need. We wanted to use this in an @Before test method which would print out the name of the current test to the console. At this point in the execution, the stack trace does not have the test method. :-(

We'll keep on using the @RunWith....

Posted by Eric Raymond on December 12, 2009 at 04:15 PM PST #

Post a Comment:
Comments are closed for this entry.
About

Tor Norbye

Search

Archives
« April 2014
SunMonTueWedThuFriSat
  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
   
       
Today