I'm using TestNG plugin for Eclipse, and I'm trying to keep the test running independent of the result. I tried with invocation count but it's only for a set number, I used IAnnotationTransformer to change it, but it is also invoked only once (the transformer).
@Override
public void transform(ITestAnnotation annotation, Class testClass, Constructor testConstructor, Method testMethod) {
// TODO Auto-generated method stub
IAnnotationTransformer.super.transform(annotation, testClass, testConstructor, testMethod);
System.out.println("Transform started");
annotation.setInvocationCount(2);
}
So after this it runs two times, but I need the test to run unknown number of times dependent on a calculation. I know I can calculate it and use it as a constant value, but I would like to keep incrementing the invocation count as long as the timer is not up.
I have also tried it with IRetryAnalyer but that is only for failed cases, and making the test appear as failed is too hacky for me.
I tried using DataProvider but it seems it is also invoked only once, where my idea was for the data provider to check the timer and return an array with an extra empty param.
Another idea was to implement increment logic in afterInvocation but that also failed :(
@Override
public void afterInvocation(IInvokedMethod method, ITestResult testResult, ITestContext context) {
// TODO Auto-generated method stub
IInvokedMethodListener.super.afterInvocation(method, testResult, context);
method.getTestMethod().setInvocationCount(getCount() + 1);
}
So, I'm out of options. The end goal is to re-run the test (pass or fail) for let's say 24 hours, the invocation number is unknown since a single test can last from 45 minutes up to 3 hours.
EDIT 1: Retry logic in TestInvoker.class ===> handleInvocationResults()
boolean willRetry =
retryAnalyzer != null
&& status == ITestResult.FAILURE
&& failure.instances != null
&& retryAnalyzer.retry(testResult);
I managed to get a part of desired behavior by implementing my listener. As you can see from the beforeInvocation I kill the runtime, which results in teardown methods and procedures not to get called.
I managed another solution with @beforeMethod but that way the remaining invocations are just skipped which is also out of the question since there is no need in invoking them after the timer is out.
public class CoreListener implements IAnnotationTransformer, IInvokedMethodListener, ITestListener {
// The invocation count has to be higher than is realistically possible to invoke within a week
private final int unrealisticInvocationCount = 1000;
private static final long durationTime = 3000;
private static long startTime = 0;
public CoreListener() {
CoreListener.startTime = System.currentTimeMillis();
}
@Override
public void transform(ITestAnnotation annotation, Class testClass, Constructor testConstructor, Method testMethod) {
IAnnotationTransformer.super.transform(annotation, testClass, testConstructor, testMethod);
System.err.println("Transformer invoked from CoreListener");
annotation.setInvocationCount(unrealisticInvocationCount);
}
@Override
public void beforeInvocation(IInvokedMethod method, ITestResult testResult, ITestContext context) {
if (method.getTestMethod().isTest()) {
if (!isAllowedToRun()) {
Runtime.getRuntime().exit(0);
}
System.err.println("beforeInvocation invoked from StabilityTimingListener");
System.out.println("Is allowed to run: " + isAllowedToRun());
}
}
@Override
public void afterInvocation(IInvokedMethod method, ITestResult testResult, ITestContext context) {
System.err.println("After invocation invoked from StabilityTimingListener");
}
public boolean isAllowedToRun() {
if (System.currentTimeMillis() > startTime + durationTime) {
return false;
}
return true;
}
}