Over a million developers have joined DZone.

How To Exclude Methods In TestNG: IMethodSelector

DZone's Guide to

How To Exclude Methods In TestNG: IMethodSelector

Free Resource
How to exclude methods in TestNG ?

Details are in the javadoc associated with the code below: one java class: copy-paste it (in a 'test' package) and run it (Java5 or 6, TestNG 5.8). You need to add testng-jdk5.jar to your classpath.

This class is also written in response to a StackOverflow Code Challenge.

package test;

import java.lang.annotation.Annotation;
import java.util.List;
import java.util.Map;

import org.testng.IMethodSelector;
import org.testng.IMethodSelectorContext;
import org.testng.ISuite;
import org.testng.ITestListener;
import org.testng.ITestNGMethod;
import org.testng.ITestRunnerFactory;
import org.testng.TestNG;
import org.testng.TestNGCommandLineArgs;
import org.testng.TestNGException;
import org.testng.TestRunner;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
import org.testng.reporters.JUnitXMLReporter;
import org.testng.reporters.TestHTMLReporter;
import org.testng.xml.XmlMethodSelector;
import org.testng.xml.XmlTest;

 * Allow to mark all @Test annotated public method, and avoid un-annotated public methods. 
* In response to a code challenge on StackOverflow, where the goal is to * "specify a class wide group on a TestNG test case".
* The @Test annotation on the base class is the righ move, BUT it would also includes public methods * not annotated as Test methods.

* This shows how to refine the Method lists by using a custom MethodSelector in TestNG (5.8). * @author VonC */ @Test(groups = { "aGlobalGroup" }) public class Base { /** * */ @BeforeClass public final void setUp() { System.out.println("Base class: @BeforeClass"); } /** * Test not part a 'aGlobalGroup', but still included in that group due to the class annotation.
* Will be executed even if the TestNG class tested is a sub-class. */ @Test(groups = { "aLocalGroup" }) public final void aFastTest() { System.out.println("Base class: Fast test"); } /** * Test not part a 'aGlobalGroup', but still included in that group due to the class annotation.
* Will be executed even if the TestNG class tested is a sub-class. */ @Test(groups = { "aLocalGroup" }) public final void aSlowTest() { System.out.println("Base class: Slow test"); //throw new IllegalArgumentException("oups"); } /** * Should not be executed.
* Yet the global annotation Test on the class would include it in the TestNG methods... */ public final void notATest() { System.out.println("Base class: NOT a test"); } /** * SubClass of a TestNG class. Some of its methods are TestNG methods, other are not.
* The goal is to check if a group specify in the super-class will include methods of this class.
* And to avoid including too much methods, such as public methods not intended to be TestNG methods. * @author VonC */ public static class Extended extends Base { /** * Test not part a 'aGlobalGroup', but still included in that group due to the super-class annotation.
* Will be executed even if the TestNG class tested is a sub-class. */ @Test public final void anExtendedTest() { System.out.println("Extended class: An Extended test"); } /** * Should not be executed.
* Yet the global annotation Test on the class would include it in the TestNG methods... */ public final void notAnExtendedTest() { System.out.println("Extended class: NOT an Extended test"); } } /** * a TestRunnerFactory is needed to register a custom XmlMethodSelector to the XMLTest.
* That XmlMethodSelector will be used to build a IMethodSelector * @author VonC */ public static class MyTestRunnerFactory implements ITestRunnerFactory { /** * Register a custom XmlMethodSelector.
* One with high priority, executed before other (default) XmlMethodSelector. * @see org.testng.ITestRunnerFactory#newTestRunner(org.testng.ISuite, org.testng.xml.XmlTest) */ @Override public final TestRunner newTestRunner(final ISuite aSuite, final XmlTest anXMLTest) { final XmlMethodSelector anXmlMethodSelector = new XmlMethodSelector(); anXmlMethodSelector.setName(MyMethodSelector.class.getName()); anXmlMethodSelector.setPriority(1); anXMLTest.getMethodSelectors().add(anXmlMethodSelector); // rest is a copy of the super() method. final TestRunner runner = new TestRunner(aSuite, anXMLTest, false /*skipFailedInvocationCounts */); runner.addListener(new TestHTMLReporter()); runner.addListener(new JUnitXMLReporter()); return runner; } } /** * Custom MethodSelector to avoid selecting non-annotated public methods.
* That way, a global Test annotation at the class level does not parasite non-test methods. * @author VonC */ public static class MyMethodSelector implements IMethodSelector { /** * default serial ID. */ private static final long serialVersionUID = 1L; /** * Any public non-annotated method will be ignored by all MethodSelector.
* Any other one will be ignore, but only be this MethodSelector. Other might select them. * @see org.testng.IMethodSelector#includeMethod(org.testng.IMethodSelectorContext, org.testng.ITestNGMethod, boolean) */ @Override public final boolean includeMethod(final IMethodSelectorContext context, final ITestNGMethod method, final boolean isTestMethod) { System.out.println(method.getMethodName() + ": " + method.isTest() + "****** " + stringArrayToString(method.getGroups())); boolean stop = true; final Annotation[] someAnnotations = method.getMethod().getAnnotations(); for (int i = 0; i < someAnnotations.length; i++) { final Annotation anAnnotation = someAnnotations[i]; if(anAnnotation instanceof Test) { stop = false; break; } } //stop = false; // if this line is un-commented, all methods are taken into account if(stop) { System.out.println("IGNORE AND EXCLUDE not-annotated public method '" + method.getMethodName() + "'"); context.setStopped(true); } return false; } private static String stringArrayToString(final String[] aStringArray) { final StringBuilder msg = new StringBuilder("["); if(aStringArray != null) { for (int i = 0; i < aStringArray.length; i++) { msg.append(aStringArray[i]); if(i<(aStringArray.length-1)) { msg.append(", "); } } } msg.append("]"); return msg.toString(); } private List testMethods; /** * @see org.testng.IMethodSelector#setTestMethods(java.util.List) */ @Override public final void setTestMethods(final List someTestMethods) { this.testMethods = someTestMethods; System.out.println(this.testMethods); } } /** * Custom TestNG needed because the original TestNG does not interpret the -testrunfactory option.
* That bug has been reported * two years ago... * @author VonC */ public static class MyTestNG extends TestNG { /** * The TestNG entry point for command line execution.
* Execute a TestNG on Extended class for the group 'aGlobalGroup'. * @param argv the TestNG command line parameters. */ public static void main(final String[] argv) { System.out.println("77743332111".replaceAll("(\\d)\\1+", "$1")); final String[] myArgv = new String[] { "-groups", "aGlobalGroup", "-testclass", "test.Base$Extended", "-suitename", "TestNG tests", "-testname", "Group Inheritance", "-testrunfactory", "test.Base$MyTestRunnerFactory", "-log", "10" }; final TestNG testng = privateMain(myArgv, null); System.exit(testng.getStatus()); } /** * Make sure that MyTestNG is created by the main TESTNG function.
* That way, {@link MyTestNG#configure(Map)} is called, and tesntgfactory is taken into account. * @param argv * @param listener * @return MyTestNG instance, with a TestRunnerFactory created if specified. */ @SuppressWarnings("unchecked") public static TestNG privateMain(final String[] argv, final ITestListener listener) { final Map arguments= checkConditions(TestNGCommandLineArgs.parseCommandLine(argv)); final MyTestNG result = new MyTestNG(); if (null != listener) { result.addListener(listener); } result.configure(arguments); try { result.run(); } catch(final TestNGException ex) { if (TestRunner.getVerbose() > 1) { ex.printStackTrace(System.out); } else { System.err.println("[ERROR]: " + ex.getMessage()); } result.setStatus(HAS_FAILURE); } return result; } @Override protected final void setStatus(final int status) { super.setStatus(status); } /** * Configure the TestNG instance by reading the settings provided in the map.
* Takes into the TESTRUNNER_FACTORY_COMMAND_OPT, which is still ignored * even after being * reported missing to Cedric BEUST. * @param cmdLineArgs map of settings * @see TestNGCommandLineArgs for setting keys */ @Override @SuppressWarnings({"unchecked"}) public final void configure(final Map cmdLineArgs) { super.configure(cmdLineArgs); final Class aTestRunnerFactoryClass = (Class) cmdLineArgs.get(TestNGCommandLineArgs.TESTRUNNER_FACTORY_COMMAND_OPT); if(aTestRunnerFactoryClass != null) { setTestRunnerFactoryClass(aTestRunnerFactoryClass); } } } /** * Redirection to the main of MyTestNG.
* All TestNG parameters are hard-coded there. * @param argv */ public static void main(final String[] argv) { MyTestNG.main(argv); } }


Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}