È necessario prestare attenzione quando si tiene sui valori passati in ascoltatori come IInvokedMethodListener
come implementazione ingenuo (compresi quelli nelle risposte già esistenti) non sarà thread-safe. Poiché TestNG può eseguire test contemporaneamente, è possibile vedere il valore memorizzato da un ascoltatore di un test diverso. Ecco un esempio con due test, testA()
e testB()
:
beforeInvocation(testA)
negozi testA
beforeInvocation(testB)
negozi testB
sovrascrivendo testA
testA()
recupera testB
(!!)
testB()
recupera testB
La classe TestMethodCapture
di seguito gestisce correttamente questa condizione di competizione associando l'ascoltatore e il relativo test tramite uno ThreadLocal
, assicurando che i test in esecuzione simultanea non si sovrascrivano l'un l'altro.
Ancora meglio, non è limitato al solo recupero il nome del test, contiene un riferimento a entrambe le istanze ITestNGMethod
e ITestResult
associati alla corrente di prova, in modo da poter anche ispezionare il metodo di class, test groups e parameters.
Si può usare in questo modo:
@Listeners(TestMethodCapture.class)
public class TestMethodCaptureTest {
@Test
public void fooBar() {
// will print "fooBar"
System.out.println(TestMethodCapture.getTestMethod().getMethodName());
}
}
Ed ecco la classe stessa:
/**
* 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());
}
}
Se non si utilizza Guava (perché no ??) è possibile aggiungere un metodo checkNotNUll()
come questo per rendere questo compile:
private static <T> T checkNotNull(T o, String msg, Object param) {
if (o == null) {
throw new NullPointerException(String.format(msg, param));
}
return o;
}
Questa risposta è molto vecchia. La risposta di Dmitry è la più semplice e richiede meno sforzo. – gorbysbm