Rich,
Perhaps you could use a MethodInterceptor implementation that would do this for you.
Basically the idea is to use the method interceptor to decide if a method should be included or not.
You would ONLY include those methods, that are NOT part of interface definitions.
Below is a very basic implementation of how to do this [ This implementation does NOT deal with test class inheritances wherein your test class has a base class from which you get a bunch of interface definitions ]
import org.testng.IMethodInstance;
import org.testng.IMethodInterceptor;
import org.testng.ITestContext;
import org.testng.ITestNGMethod;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
public class MyTransformer implements IMethodInterceptor {
@Override
public List<IMethodInstance> intercept(List<IMethodInstance> methods, ITestContext context) {
//Lets first collect all the classes that are involved.
List<Class<?>> classes = methods.stream()
.map(it -> it.getInstance().getClass())
.distinct()
.collect(Collectors.toList());
//We now create a map of Class to methods.
//Here the methods are ONLY those methods that are coming from an interface that a class implements.
Map<Class<?>, List<Method>> classToInterfaceImplsMapping = new ConcurrentHashMap<>();
for (Class<?> klass : classes) {
//First lets extract out all the interfaces that this class implements.
List<Class<?>> interfaces = Arrays.stream(klass.getInterfaces()).toList();
//Now let's extract all the methods that are part of all the interface definitions.
List<Method> methodsInInterfaces = extractMethodsInInterfaces(interfaces);
classToInterfaceImplsMapping.computeIfAbsent(klass, k -> new ArrayList<>())
.addAll(methodsInInterfaces);
}
return methods.stream()
.filter(it -> include(it, classToInterfaceImplsMapping)) //Skip interface implementations
.collect(Collectors.toList());
}
private static List<Method> extractMethodsInInterfaces(List<Class<?>> interfaces) {
return interfaces.stream()
.flatMap(it -> Arrays.stream(it.getDeclaredMethods()))
.collect(Collectors.toList());
}
private static boolean include(IMethodInstance methodInstance, Map<Class<?>, List<Method>> classToInterfaceImplsMapping) {
ITestNGMethod itm = methodInstance.getMethod();
Method m = itm.getConstructorOrMethod().getMethod();
Class<?> belongingClass = methodInstance.getInstance().getClass();
//First extract all the interface method definitions for our class.
//Then stream it and ensure that none of those methods matches with our test method
boolean result = classToInterfaceImplsMapping.get(belongingClass)
.stream()
.noneMatch(it -> bothMethodsSame(it, m));
System.err.println("Include " + itm.getQualifiedName() + "? " + result);
return result;
}
private static boolean bothMethodsSame(Method first, Method second) {
if (!first.getName().equals(second.getName())) {
return false;
}
if (!first.getReturnType().equals(second.getReturnType())) {
return false;
}
return equalParamTypes(first.getParameterTypes(), second.getParameterTypes());
}
private static boolean equalParamTypes(Class<?>[] params1, Class<?>[] params2) {
if (params1.length != params2.length) {
return false;
}
for (int i = 0; i < params1.length; i++) {
if (!params1[i].equals(params2[i])) {
return false;
}
}
return true;
}
}
Thanks & Regards
Krishnan Mahadevan
"All the desirable things in life are either illegal, expensive, fattening or in love with someone else!"
My Scribblings @ http://wakened-cognition.blogspot.com/