Retrieve test name on TestNG
Asked Answered
A

6

23

Can I retrieve currently running test name like in JUnit (using getName() or rules)?

@Test
public void fooBar(){
     System.out.println(magic()); //should print "fooBar"
}

P.S. I don't want use some self-written tool based on stack traces.

Apex answered 21/12, 2011 at 21:28 Comment(0)
C
6

According the to TestNG documentation at: http://testng.org/doc/documentation-main.html you can implement listeners that might be able to help you with your problem.

Look at section 5.16 TestNG Listeners, and in particular the IInvokedMethodListener (javadoc: http://testng.org/javadocs/org/testng/IInvokedMethodListener.html). You can hook into the beforeInvocation to grab the method name, hold onto it somewhere, and then use it in your test. You could of course, just use the the details immediately in your listener implementation.

Carton answered 21/12, 2011 at 23:35 Comment(1)
This answer is very old. Dmitry's answer is the most straightforward one requiring least effort.Bield
N
62

I found better solution with @BeforeMethod annotation:

import java.lang.reflect.Method;

public class Test
{ 

    @BeforeMethod
    public void handleTestMethodName(Method method)
    {
        String testName = method.getName(); 
        ...
    }

    ...
}

(based on solution from this thread)

Nader answered 30/8, 2012 at 17:37 Comment(0)
C
15

When you use TestNG you can use @BeforeTest annotation

Try set test name in testng.xml file test tag:

<test name="Check name test" >

and use this metod:

@BeforeTest
public void startTest(final ITestContext testContext) {
    System.out.println(testContext.getName()); // it prints "Check name test"
}
Compote answered 7/2, 2014 at 14:54 Comment(0)
C
9

Declare an ITestContext in parameter in your method and grab whatever information you need from it.

Collete answered 22/12, 2011 at 5:45 Comment(2)
Actually I can't find it in this interface context/suite/currentXmlTest name doesn't contain this information.Apex
Your question is more a Java question than a TestNG one, and since you don't want to use the only way that I know to do it (walk the stack trace), I'm not sure what else to say...Collete
C
6

According the to TestNG documentation at: http://testng.org/doc/documentation-main.html you can implement listeners that might be able to help you with your problem.

Look at section 5.16 TestNG Listeners, and in particular the IInvokedMethodListener (javadoc: http://testng.org/javadocs/org/testng/IInvokedMethodListener.html). You can hook into the beforeInvocation to grab the method name, hold onto it somewhere, and then use it in your test. You could of course, just use the the details immediately in your listener implementation.

Carton answered 21/12, 2011 at 23:35 Comment(1)
This answer is very old. Dmitry's answer is the most straightforward one requiring least effort.Bield
M
6

You need to be careful when holding onto the values passed into listeners like IInvokedMethodListener as a naive implementation (including those in existing answers) will not be thread-safe. Since TestNG can run tests concurrently it's possible to see the stored value from a different test's listener. Here's an example with two tests, testA() and testB():

  1. beforeInvocation(testA) stores testA
  2. beforeInvocation(testB) stores testB overwriting testA
  3. testA() retrieves testB (!!)
  4. testB() retrieves testB

The TestMethodCapture class below handles this race condition correctly by associating the listener and its test via a ThreadLocal, ensuring that concurrently running tests will not overwrite each other.

Even better, it's not limited to just retrieving the test's name, it holds a reference to both the ITestNGMethod and ITestResult instances associated with the current test, so you can also inspect the method's class, test groups, and parameters.

You can use it like so:

@Listeners(TestMethodCapture.class)
public class TestMethodCaptureTest {
  @Test
  public void fooBar() {
    // will print "fooBar"
    System.out.println(TestMethodCapture.getTestMethod().getMethodName());
  }
}

And here's the class itself:

/**
 * Captures the currently executing test method so it can be accessed by the test,
 * e.g. to retrieve the test method's name. This class is thread-safe.
 *
 * <p>Register this class as a
 * <a href="http://testng.org/doc/documentation-main.html#testng-listeners">TestNG
 * listener</a>, then access the method and result from test code with the static
 * {@link #getTestMethod} and {@link #getTestResult} methods.
 * 
 * <p>Annotating a test class with {@code @Listeners(TestMethodCapture.class)} is the
 * suggested way to enable capturing if your test's correctness will depend on this
 * listener being enabled.
 */
public class TestMethodCapture implements IInvokedMethodListener {
  private static ThreadLocal<ITestNGMethod> currentMethods = new ThreadLocal<>();
  private static ThreadLocal<ITestResult> currentResults = new ThreadLocal<>();

  @Override
  public void beforeInvocation(IInvokedMethod method, ITestResult testResult) {
    currentMethods.set(method.getTestMethod());
    currentResults.set(testResult);
  }

  @Override
  public void afterInvocation(IInvokedMethod method, ITestResult testResult) {
    currentMethods.remove();
    currentResults.remove();
  }

  public static ITestNGMethod getTestMethod() {
    return checkNotNull(currentMethods.get(),
      "Did you forget to register the %s listener?", TestMethodCapture.class.getName());
  }

  /**
   * Parameters passed from a data provider are accessible in the test result.
   */
  public static ITestResult getTestResult() {
    return checkNotNull(currentResults.get(),
      "Did you forget to register the %s listener?", TestMethodCapture.class.getName());
  }
}

If you aren't using Guava (why not??) you can add a checkNotNUll() method like this to make this compile:

private static <T> T checkNotNull(T o, String msg, Object param) {
  if (o == null) {
    throw new NullPointerException(String.format(msg, param));
  }
  return o;
}
Metastasize answered 4/6, 2016 at 22:53 Comment(2)
Can you please explain the checkNotNull method that is being returned? Should we define the method? It shows an error that this method is not defined.Keys
@Keys sorry I missed your comment. checkNotNull() is coming from Guava. I would strongly encourage using this library in any Java project, but this method is essentially a nice wrapper around if (foo == null) throw NullPointerException(); so you could just replace these calls with a similar conditional.Metastasize
R
0

Easiest way is to use Reporter.getCurrentTestResult().getName();. This gives you the name of the currently running test.

This is especially useful when you want to retrieve the test name from some common utility or logging class and don't want to force all your tests to pass the name.

Retortion answered 8/8 at 18:23 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.