This is an automated email from the git hooks/post-receive script. eugene-guest pushed a commit to branch master in repository testng.
commit 24006fbed5a964515ba0f0dd6e1c05b06af5ba57 Author: Eugene Zhukov <[email protected]> Date: Fri Jan 23 20:28:59 2015 +0000 Import upstream version 6.8.17 --- CHANGES.txt | 7 +- README.dev | 16 +- build.properties | 2 +- build.xml | 1 + doc/documentation-main.html | 4 +- doc/index.html | 4 +- pom-test.xml | 2 +- pom.xml | 2 +- src/main/java/org/testng/Reporter.java | 21 +- src/main/java/org/testng/TestRunner.java | 2 - src/main/java/org/testng/collections/Lists.java | 5 +- src/main/java/org/testng/internal/ClassHelper.java | 22 +- src/main/java/org/testng/internal/IInvoker.java | 6 +- src/main/java/org/testng/internal/Invoker.java | 507 +++++++++------------ .../org/testng/internal/MethodGroupsHelper.java | 55 ++- .../testng/internal/MethodInvocationHelper.java | 28 +- src/main/java/org/testng/internal/Parameters.java | 52 +-- .../TestMethodWithDataProviderMethodWorker.java | 45 +- .../java/org/testng/internal/TestMethodWorker.java | 15 +- .../internal/annotations/JDK15TagFactory.java | 25 +- .../org/testng/reporters/FileStringBuffer.java | 6 + .../java/org/testng/reporters/XMLStringBuffer.java | 4 +- src/main/java/org/testng/xml/XmlSuite.java | 20 +- src/main/java/org/testng/xml/XmlTest.java | 18 +- .../test/InvocationAndSuccessPercentageTest.java | 4 +- .../test/dataprovider/DataProviderWithError.java | 25 + .../test/dataprovider/FailingDataProviderTest.java | 15 +- src/test/java/test/testng106/TestNG106.java | 6 +- src/test/resources/testng-single.xml | 9 +- 29 files changed, 460 insertions(+), 468 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt index 3f18f1d..e1e85ec 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,6 +1,11 @@ Current -Fixed: GITHUB-376: Some results can be lost (Konstantin Savin) +6.8.15: + +Fixed: OutOfMemoryException while generating reports. +Fixed: GITHUB-566: Build does not fail when successPercentage for @Test is not met +Fixed: XmlTest#setGroupInstances was not being shown in toXml(). +Fixed: GITHUB-376: Some results can be lost (Konstantin Savin). Fixed: Handle relative paths of Suite XML files properly (Nalin Makar) 6.8.5: diff --git a/README.dev b/README.dev index a26a7e9..c74f7e5 100644 --- a/README.dev +++ b/README.dev @@ -13,12 +13,24 @@ Send the public key: Configure ~/.m2/settings.xml with Nexus user/password: + <settings> <servers> <server> + <id>sonatype-nexus-snapshots</id> + <username>***</username> + <password>***</password> + </server> + <server> <id>sonatype-nexus-staging</id> - <username>xxx</username> - <password>xxx</password> + <username>***</username> + <password>***</password> </server> </servers> </settings> + +Snaphot deploy: +mvn -Dgpg.passphrase= -Dgpg.keyname=<public_key> deploy + +Staging deploy: +mvn -Dgpg.passphrase= -Dgpg.keyname=<public_key> release:clean release:prepare release:perform diff --git a/build.properties b/build.properties index 085a02d..f4309d8 100644 --- a/build.properties +++ b/build.properties @@ -2,7 +2,7 @@ # TestNG distribution # testng.basename=testng -testng.version=6.8.8 +testng.version=6.8.14-SNAPSHOT testng.fullname=${testng.basename}-${testng.version} # diff --git a/build.xml b/build.xml index 63477cc..7f8059c 100644 --- a/build.xml +++ b/build.xml @@ -33,6 +33,7 @@ <!-- java greater than 1.5 required to build --> <condition property="requiredJavaVersion"> <or> + <equals arg1="${ant.java.version}" arg2="1.8" /> <equals arg1="${ant.java.version}" arg2="1.7" /> <equals arg1="${ant.java.version}" arg2="1.6" /> </or> diff --git a/doc/documentation-main.html b/doc/documentation-main.html index 9a372bf..36a661a 100644 --- a/doc/documentation-main.html +++ b/doc/documentation-main.html @@ -1425,9 +1425,9 @@ signOut("uk") For this ordering, you can use the XML attribute <tt>group-by-instances</tt>. This attribute is valid either on <suite> or <test>: <pre class="brush: xml"> - <suite name="Factory" order-by-instances="true"> + <suite name="Factory" group-by-instances="true"> or - <test name="Factory" order-by-instances="true"> + <test name="Factory" group-by-instances="true"> </pre> diff --git a/doc/index.html b/doc/index.html index 1b07c94..cae6a27 100644 --- a/doc/index.html +++ b/doc/index.html @@ -42,9 +42,9 @@ <p align="right"><font size="-2"><em>Cédric Beust (cedric at beust.com)<br> -Current version: 6.8.1<br> +Current version: 6.8.15<br> Created: April 27th, 2004<br> -Last Modified: March 30th, 2013</em></font></p> +Last Modified: January 14th, 2015</em></font></p> <p>TestNG is a testing framework inspired from JUnit and NUnit but introducing diff --git a/pom-test.xml b/pom-test.xml index d318865..bf83d94 100644 --- a/pom-test.xml +++ b/pom-test.xml @@ -72,7 +72,7 @@ <dependency> <groupId>org.testng</groupId> <artifactId>testng</artifactId> - <version>6.8.9-SNAPSHOT</version> + <version>6.8.13</version> <scope>test</scope> </dependency> </dependencies> diff --git a/pom.xml b/pom.xml index ac16a84..7c26d90 100644 --- a/pom.xml +++ b/pom.xml @@ -7,7 +7,7 @@ <artifactId>testng</artifactId> <packaging>jar</packaging> <name>TestNG</name> - <version>6.8.13</version> + <version>6.8.17</version> <description>TestNG is a testing framework.</description> <url>http://testng.org</url> diff --git a/src/main/java/org/testng/Reporter.java b/src/main/java/org/testng/Reporter.java index 01f8f36..b2f30eb 100755 --- a/src/main/java/org/testng/Reporter.java +++ b/src/main/java/org/testng/Reporter.java @@ -1,13 +1,13 @@ package org.testng; -import org.testng.collections.Lists; -import org.testng.collections.Maps; -import org.testng.util.Strings; - import java.util.List; import java.util.Map; import java.util.Vector; +import org.testng.collections.Lists; +import org.testng.collections.Maps; +import org.testng.util.Strings; + /** * This class is used for test methods to log messages that will be * included in the HTML reports generated by TestNG. @@ -18,8 +18,8 @@ import java.util.Vector; * <br> * The reporter keeps a combined output of strings (in m_output) and also * a record of which method output which line. In order to do this, callers - * specify what the current method is with setCurrentMethod() and the - * Reporter maintaing a mapping of each method with a list of integers. + * specify what the current method is with setCurrentTestResult() and the + * Reporter maintaing a mapping of each test result with a list of integers. * These integers are indices in the combined output (avoids duplicating * the output). * @@ -37,7 +37,8 @@ public class Reporter { */ private static List<String> m_output = new Vector<String>(); - private static Map<ITestResult, List<Integer>> m_methodOutputMap = Maps.newHashMap(); + /** The key is the hashCode of the ITestResult */ + private static Map<Integer, List<Integer>> m_methodOutputMap = Maps.newHashMap(); private static boolean m_escapeHtml = false; @@ -72,10 +73,10 @@ public class Reporter { // synchronization needed to ensure the line number and m_output are updated atomically int n = getOutput().size(); - List<Integer> lines = m_methodOutputMap.get(m); + List<Integer> lines = m_methodOutputMap.get(m.hashCode()); if (lines == null) { lines = Lists.newArrayList(); - m_methodOutputMap.put(m, lines); + m_methodOutputMap.put(m.hashCode(), lines); } lines.add(n); getOutput().add(s); @@ -144,7 +145,7 @@ public class Reporter { public static synchronized List<String> getOutput(ITestResult tr) { List<String> result = Lists.newArrayList(); - List<Integer> lines = m_methodOutputMap.get(tr); + List<Integer> lines = m_methodOutputMap.get(tr.hashCode()); if (lines != null) { for (Integer n : lines) { result.add(getOutput().get(n)); diff --git a/src/main/java/org/testng/TestRunner.java b/src/main/java/org/testng/TestRunner.java index 1f2936b..49daa5f 100644 --- a/src/main/java/org/testng/TestRunner.java +++ b/src/main/java/org/testng/TestRunner.java @@ -899,7 +899,6 @@ public class TestRunner methodInstances.toArray(new IMethodInstance[methodInstances.size()]), m_xmlTest.getSuite(), m_xmlTest.getAllParameters(), - m_allTestMethods, m_groupMethods, m_classMethodMap, this); @@ -938,7 +937,6 @@ public class TestRunner findClasses(methodInstances, c), m_xmlTest.getSuite(), params, - m_allTestMethods, m_groupMethods, m_classMethodMap, this); diff --git a/src/main/java/org/testng/collections/Lists.java b/src/main/java/org/testng/collections/Lists.java index a0cba2d..2b5eaec 100755 --- a/src/main/java/org/testng/collections/Lists.java +++ b/src/main/java/org/testng/collections/Lists.java @@ -2,6 +2,7 @@ package org.testng.collections; import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; import java.util.List; public class Lists { @@ -16,9 +17,7 @@ public class Lists { public static <K> List<K> newArrayList(K... elements) { List<K> result = new ArrayList<K>(); - for (K e : elements) { - result.add(e); - } + Collections.addAll(result, elements); return result; } diff --git a/src/main/java/org/testng/internal/ClassHelper.java b/src/main/java/org/testng/internal/ClassHelper.java index b919d55..42b4eb4 100644 --- a/src/main/java/org/testng/internal/ClassHelper.java +++ b/src/main/java/org/testng/internal/ClassHelper.java @@ -86,9 +86,7 @@ public final class ClassHelper { allClassLoaders.addAll(m_classLoaders); } - int count = 0; for (ClassLoader classLoader : allClassLoaders) { - ++count; if (null == classLoader) { continue; } @@ -133,13 +131,9 @@ public final class ClassHelper { ConstructorOrMethod result = null; for (Method method : cls.getMethods()) { - IFactoryAnnotation f = (IFactoryAnnotation) finder.findAnnotation(method, - IFactoryAnnotation.class); + IFactoryAnnotation f = finder.findAnnotation(method, IFactoryAnnotation.class); if (null != f) { - if (result != null) { - throw new TestNGException(cls.getName() + ": only one @Factory method allowed"); - } result = new ConstructorOrMethod(method); result.setEnabled(f.getEnabled()); break; @@ -323,8 +317,7 @@ public final class ClassHelper { // Constructor<?> constructor = findAnnotatedConstructor(finder, declaringClass); if (null != constructor) { - IParametersAnnotation annotation = (IParametersAnnotation) finder.findAnnotation(constructor, - IParametersAnnotation.class); + IParametersAnnotation annotation = finder.findAnnotation(constructor, IParametersAnnotation.class); String[] parameterNames = annotation.getValue(); Object[] parameters = Parameters.createInstantiationParameters(constructor, @@ -374,12 +367,12 @@ public final class ClassHelper { parameters = new Object[] { enclosingClassInstance }; } // isStatic - Constructor<?> ct = null; + Constructor<?> ct; try { ct = declaringClass.getDeclaredConstructor(parameterTypes); } catch (NoSuchMethodException ex) { - ct = declaringClass.getDeclaredConstructor(new Class[] {String.class}); + ct = declaringClass.getDeclaredConstructor(String.class); parameters = new Object[] { "Default test name" }; // If ct == null here, we'll pass a null // constructor to the factory and hope it can deal with it @@ -442,8 +435,7 @@ public final class ClassHelper { Constructor<?>[] constructors = declaringClass.getDeclaredConstructors(); for (Constructor<?> result : constructors) { - IParametersAnnotation annotation = (IParametersAnnotation) - finder.findAnnotation(result, IParametersAnnotation.class); + IParametersAnnotation annotation = finder.findAnnotation(result, IParametersAnnotation.class); if (null != annotation) { String[] parameters = annotation.getValue(); @@ -471,8 +463,8 @@ public final class ClassHelper { return null; } - Constructor<T> ctor = declaringClass.getConstructor(new Class[] { String.class }); - result = ctor.newInstance(new Object[] { "Default test name" }); + Constructor<T> ctor = declaringClass.getConstructor(String.class); + result = ctor.newInstance("Default test name"); } catch (Exception e) { String message = e.getMessage(); diff --git a/src/main/java/org/testng/internal/IInvoker.java b/src/main/java/org/testng/internal/IInvoker.java index b3ad180..98cda2e 100755 --- a/src/main/java/org/testng/internal/IInvoker.java +++ b/src/main/java/org/testng/internal/IInvoker.java @@ -37,8 +37,6 @@ public interface IInvoker { * Invoke the given method * * @param testMethod - * @param allTestMethods The list of all the test methods - * @param methodIndex The index of testMethod in the allTestMethods array * @param suite * @param parameters * @param groupMethods @@ -46,12 +44,10 @@ public interface IInvoker { * @return a list containing the results of the test methods invocations */ public List<ITestResult> invokeTestMethods(ITestNGMethod testMethod, - ITestNGMethod[] allTestMethods, - int methodIndex, XmlSuite suite, Map<String, String> parameters, ConfigurationGroupMethods groupMethods, - Object[] instances, + Object instance, ITestContext testContext); } diff --git a/src/main/java/org/testng/internal/Invoker.java b/src/main/java/org/testng/internal/Invoker.java index 6d55292..4b46ac9 100644 --- a/src/main/java/org/testng/internal/Invoker.java +++ b/src/main/java/org/testng/internal/Invoker.java @@ -43,6 +43,8 @@ import java.lang.annotation.Annotation; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.Map; @@ -171,11 +173,11 @@ public class Invoker implements IInvoker { IConfigurationAnnotation configurationAnnotation= null; try { - Object[] instances= tm.getInstances(); - if (instances == null || instances.length == 0) { - instances = new Object[] { instance }; + Object inst = tm.getInstance(); + if (inst == null) { + inst = instance; } - Class<?> objectClass= instances[0].getClass(); + Class<?> objectClass= inst.getClass(); Method method= tm.getMethod(); // Only run the configuration if @@ -206,11 +208,11 @@ public class Invoker implements IInvoker { testMethodResult); testResult.setParameters(parameters); - Object[] newInstances= (null != instance) ? new Object[] { instance } : instances; + Object newInstance = null != instance ? instance: inst; runConfigurationListeners(testResult, true /* before */); - invokeConfigurationMethod(newInstances, tm, + invokeConfigurationMethod(newInstance, tm, parameters, isClassConfiguration, isSuiteConfiguration, testResult); // TODO: probably we should trigger the event for each instance??? @@ -320,13 +322,10 @@ public class Invoker implements IInvoker { { Throwable cause= ite.getCause() != null ? ite.getCause() : ite; - if(SkipException.class.isAssignableFrom(cause.getClass())) { - SkipException skipEx= (SkipException) cause; - if(skipEx.isSkip()) { - testResult.setThrowable(skipEx); - handleConfigurationSkip(tm, testResult, annotation, currentTestMethod, instance, suite); - return; - } + if(isSkipExceptionAndSkip(cause)) { + testResult.setThrowable(cause); + handleConfigurationSkip(tm, testResult, annotation, currentTestMethod, instance, suite); + return; } Utils.log("", 3, "Failed to invoke configuration method " + tm.getRealClass().getName() + "." + tm.getMethodName() + ":" + cause.getMessage()); @@ -501,7 +500,7 @@ public class Invoker implements IInvoker { * TODO: Should change this method to be more like invokeMethod() so that we can * handle calls to {@code IInvokedMethodListener} better. * - * @param instances the instances to invoke the configuration method on + * @param targetInstance the instance to invoke the configuration method on * @param tm the configuration method * @param params the parameters needed for method invocation * @param isClass flag if the configuration method is a class level method // FIXME: this looks like a missusage @@ -509,7 +508,7 @@ public class Invoker implements IInvoker { * @throws InvocationTargetException * @throws IllegalAccessException */ - private void invokeConfigurationMethod(Object[] instances, + private void invokeConfigurationMethod(Object targetInstance, ITestNGMethod tm, Object[] params, boolean isClass, @@ -520,15 +519,7 @@ public class Invoker implements IInvoker { // Mark this method with the current thread id tm.setId(ThreadUtil.currentThreadInfo()); - // Only a @BeforeMethod/@AfterMethod needs to be run before each instance, all the other - // configuration methods only need to be run once - List<Object> actualInstances = Lists.newArrayList(); - if (tm.isBeforeMethodConfiguration() || tm.isAfterMethodConfiguration()) { - actualInstances.addAll(Arrays.asList(instances)); - } else { - actualInstances.add(instances[0]); - } - for(Object targetInstance : actualInstances) { + { InvokedMethod invokedMethod= new InvokedMethod(targetInstance, tm, params, @@ -544,15 +535,12 @@ public class Invoker implements IInvoker { Method method = tm.getMethod(); // - // If this method is a IHookable, invoke its run() method + // If this method is a IConfigurable, invoke its run() method // IConfigurable configurableInstance = IConfigurable.class.isAssignableFrom(tm.getMethod().getDeclaringClass()) ? (IConfigurable) targetInstance : m_configuration.getConfigurable(); if (configurableInstance != null) { - // - // If this method is a IConfigurable, invoke its run() method - // MethodInvocationHelper.invokeConfigurable(targetInstance, params, configurableInstance, method, testResult); } @@ -572,10 +560,6 @@ public class Invoker implements IInvoker { } } } - // Only run the method once if it's @BeforeSuite or @AfterSuite - if (isSuite) { - break; - } } catch (InvocationTargetException ex) { throwConfigurationFailure(testResult, ex); @@ -625,8 +609,7 @@ public class Invoker implements IInvoker { } // pass both paramValues and paramIndex to be thread safe in case parallel=true + dataprovider. - private ITestResult invokeMethod(Object[] instances, - int instanceIndex, + private ITestResult invokeMethod(Object instance, final ITestNGMethod tm, Object[] parameterValues, int parametersIndex, @@ -635,13 +618,13 @@ public class Invoker implements IInvoker { ITestClass testClass, ITestNGMethod[] beforeMethods, ITestNGMethod[] afterMethods, - ConfigurationGroupMethods groupMethods) { + ConfigurationGroupMethods groupMethods, + FailureContext failureContext) { TestResult testResult = new TestResult(); // // Invoke beforeGroups configurations // - Object instance = instances[instanceIndex]; invokeBeforeGroupsConfigurations(testClass, tm, groupMethods, suite, params, instance); @@ -688,11 +671,10 @@ public class Invoker implements IInvoker { m_notifier.addInvokedMethod(invokedMethod); - Method thisMethod= tm.getMethod(); + Method thisMethod = tm.getConstructorOrMethod().getMethod(); if(confInvocationPassed(tm, tm, testClass, instance)) { - log(3, "Invoking " + thisMethod.getDeclaringClass().getName() + "." + - thisMethod.getName()); + log(3, "Invoking " + tm.getRealClass().getName() + "." + tm.getMethodName()); // If no timeOut, just invoke the method if (MethodHelper.calculateTimeOut(tm) <= 0) { @@ -701,7 +683,7 @@ public class Invoker implements IInvoker { // If this method is a IHookable, invoke its run() method // IHookable hookableInstance = - IHookable.class.isAssignableFrom(thisMethod.getDeclaringClass()) ? + IHookable.class.isAssignableFrom(tm.getRealClass()) ? (IHookable) instance : m_configuration.getHookable(); if (hookableInstance != null) { MethodInvocationHelper.invokeHookable(instance, @@ -747,12 +729,14 @@ public class Invoker implements IInvoker { testResult.setStatus(ITestResult.FAILURE); } finally { + // Set end time ASAP + testResult.setEndMillis(System.currentTimeMillis()); + ExpectedExceptionsHolder expectedExceptionClasses = MethodHelper.findExpectedExceptions(m_annotationFinder, tm.getMethod()); - List<ITestResult> results = Lists.newArrayList(); - results.add(testResult); - handleInvocationResults(tm, results, null, 0, expectedExceptionClasses, false, - false /* collect results */); + List<ITestResult> results = Lists.<ITestResult>newArrayList(testResult); + handleInvocationResults(tm, results, expectedExceptionClasses, false, + false /* collect results */, failureContext); // If this method has a data provider and just failed, memorize the number // at which it failed. @@ -769,14 +753,13 @@ public class Invoker implements IInvoker { // tm.incrementCurrentInvocationCount(); - if (testResult != null) { - testResult.setEndMillis(System.currentTimeMillis()); - } - // Run invokedMethodListeners after updating TestResult runInvokedMethodListeners(AFTER_INVOCATION, invokedMethod, testResult); runTestListeners(testResult); - collectResults(tm, results, testResult); + // Do not notify if will retry. + if (!results.isEmpty()) { + collectResults(tm, Collections.<ITestResult>singleton(testResult)); + } // // Invoke afterMethods only if @@ -803,21 +786,21 @@ public class Invoker implements IInvoker { return testResult; } - private void collectResults(ITestNGMethod testMethod, List<ITestResult> results, TestResult testResult) { - for (int i = 0; i < results.size(); i++) { + void collectResults(ITestNGMethod testMethod, Collection<ITestResult> results) { + for (ITestResult result : results) { // Collect the results - int status = results.get(i).getStatus(); + final int status = result.getStatus(); if(ITestResult.SUCCESS == status) { - m_notifier.addPassedTest(testMethod, testResult); + m_notifier.addPassedTest(testMethod, result); } else if(ITestResult.SKIP == status) { - m_notifier.addSkippedTest(testMethod, testResult); + m_notifier.addSkippedTest(testMethod, result); } else if(ITestResult.FAILURE == status) { - m_notifier.addFailedTest(testMethod, testResult); + m_notifier.addFailedTest(testMethod, result); } else if(ITestResult.SUCCESS_PERCENTAGE_FAILURE == status) { - m_notifier.addFailedButWithinSuccessPercentageTest(testMethod, testResult); + m_notifier.addFailedButWithinSuccessPercentageTest(testMethod, result); } else { assert false : "UNKNOWN STATUS:" + status; @@ -878,10 +861,10 @@ public class Invoker implements IInvoker { * </ul> * * <p/> - * This method is also reponsible for invoking @BeforeGroup, @BeforeMethod, @AfterMethod, @AfterGroup + * This method is also responsible for invoking @BeforeGroup, @BeforeMethod, @AfterMethod, @AfterGroup * if it is the case for the passed in @Test method. */ - protected List<ITestResult> invokeTestMethod(Object[] instances, + protected ITestResult invokeTestMethod(Object instance, final ITestNGMethod tm, Object[] parameterValues, int parametersIndex, @@ -890,19 +873,16 @@ public class Invoker implements IInvoker { ITestClass testClass, ITestNGMethod[] beforeMethods, ITestNGMethod[] afterMethods, - ConfigurationGroupMethods groupMethods) + ConfigurationGroupMethods groupMethods, + FailureContext failureContext) { - List<ITestResult> results = Lists.newArrayList(); - // Mark this method with the current thread id tm.setId(ThreadUtil.currentThreadInfo()); - for(int i= 0; i < instances.length; i++) { - results.add(invokeMethod(instances, i, tm, parameterValues, parametersIndex, suite, params, - testClass, beforeMethods, afterMethods, groupMethods)); - } + ITestResult result = invokeMethod(instance, tm, parameterValues, parametersIndex, suite, params, + testClass, beforeMethods, afterMethods, groupMethods, failureContext); - return results; + return result; } /** @@ -1018,8 +998,7 @@ public class Invoker implements IInvoker { return null; } - int retryFailed(Object[] instances, - int instanceIndex, + int retryFailed(Object instance, final ITestNGMethod tm, XmlSuite suite, ITestClass testClass, @@ -1032,37 +1011,34 @@ public class Invoker implements IInvoker { ITestContext testContext, Map<String, String> parameters, int parametersIndex) { - List<Object> failedInstances; - + final FailureContext failure = new FailureContext(); + failure.count = failureCount; do { - failedInstances = Lists.newArrayList(); Map<String, String> allParameters = Maps.newHashMap(); /** * TODO: This recreates all the parameters every time when we only need * one specific set. Should optimize it by only recreating the set needed. */ ParameterBag bag = createParameters(tm, parameters, - allParameters, null, suite, testContext, null /* fedInstance */, null /* testResult */); + allParameters, suite, testContext, null /* fedInstance */); Object[] parameterValues = getParametersFromIndex(bag.parameterHolder.parameters, parametersIndex); - result.add(invokeMethod(instances, instanceIndex, tm, parameterValues,parametersIndex, suite, - allParameters, testClass, beforeMethods, afterMethods, groupMethods)); - failureCount = handleInvocationResults(tm, result, failedInstances, - failureCount, expectedExceptionHolder, true, true /* collect results */); + result.add(invokeMethod(instance, tm, parameterValues, parametersIndex, suite, + allParameters, testClass, beforeMethods, afterMethods, groupMethods, failure)); + // It's already handled inside 'invokeMethod' but results not collected + handleInvocationResults(tm, result, expectedExceptionHolder, true, true/* collect results */, failure); } - while (!failedInstances.isEmpty()); - return failureCount; + while (!failure.instances.isEmpty()); + return failure.count; } private ParameterBag createParameters(ITestNGMethod testMethod, Map<String, String> parameters, Map<String, String> allParameterNames, - Object[] parameterValues, XmlSuite suite, ITestContext testContext, - Object fedInstance, - ITestResult testResult) + Object fedInstance) { Object instance; if (fedInstance != null) { @@ -1072,9 +1048,8 @@ public class Invoker implements IInvoker { instance = testMethod.getInstance(); } - ParameterBag bag= handleParameters(testMethod, - instance, allParameterNames, parameters, parameterValues, suite, testContext, fedInstance, - testResult); + ParameterBag bag = handleParameters(testMethod, + instance, allParameterNames, parameters, null, suite, testContext, fedInstance, null); return bag; } @@ -1092,101 +1067,84 @@ public class Invoker implements IInvoker { * * Note (alex): this method can be refactored to use a SingleTestMethodWorker that * directly invokes - * {@link #invokeTestMethod(Object[], ITestNGMethod, Object[], XmlSuite, Map, ITestClass, ITestNGMethod[], ITestNGMethod[], ConfigurationGroupMethods)} + * {@link #invokeTestMethod(Object, ITestNGMethod, Object[], int, XmlSuite, Map, ITestClass, ITestNGMethod[], ITestNGMethod[], ConfigurationGroupMethods, FailureContext)} * and this would simplify the implementation (see how DataTestMethodWorker is used) */ @Override public List<ITestResult> invokeTestMethods(ITestNGMethod testMethod, - ITestNGMethod[] allTestMethods, - int testMethodIndex, XmlSuite suite, Map<String, String> testParameters, ConfigurationGroupMethods groupMethods, - Object[] instances, + Object instance, ITestContext testContext) { // Potential bug here if the test method was declared on a parent class assert null != testMethod.getTestClass() - : "COULDN'T FIND TESTCLASS FOR " + testMethod.getMethod().getDeclaringClass(); - - List<ITestResult> result = Lists.newArrayList(); + : "COULDN'T FIND TESTCLASS FOR " + testMethod.getRealClass(); if (!MethodHelper.isEnabled(testMethod.getMethod(), m_annotationFinder)) { - /* - * return if the method is not enabled. No need to do any more calculations - */ - return result; + // return if the method is not enabled. No need to do any more calculations + return Collections.emptyList(); } - ITestClass testClass= testMethod.getTestClass(); - long start = System.currentTimeMillis(); + // By the time this testMethod to be invoked, + // all dependencies should be already run or we need to skip this method, + // so invocation count should not affect dependencies check + final String okToProceed = checkDependencies(testMethod, testContext.getAllTestMethods()); + + if (okToProceed != null) { + // + // Not okToProceed. Test is being skipped + // + ITestResult result = registerSkippedTestResult(testMethod, null, System.currentTimeMillis(), + new Throwable(okToProceed)); + m_notifier.addSkippedTest(testMethod, result); + return Collections.singletonList(result); + } + + + final Map<String, String> parameters = + testMethod.findMethodParameters(testContext.getCurrentXmlTest()); + + // For invocationCount > 1 and threadPoolSize > 1 run this method in its own pool thread. + if (testMethod.getInvocationCount() > 1 && testMethod.getThreadPoolSize() > 1) { + return invokePooledTestMethods(testMethod, suite, parameters, groupMethods, testContext); + } - // For invocationCount > 1 and threadPoolSize > 1 the method will be invoked on a thread pool long timeOutInvocationCount = testMethod.getInvocationTimeOut(); //FIXME: Is this correct? boolean onlyOne = testMethod.getThreadPoolSize() > 1 || timeOutInvocationCount > 0; int invocationCount = onlyOne ? 1 : testMethod.getInvocationCount(); - int failureCount = 0; ExpectedExceptionsHolder expectedExceptionHolder = MethodHelper.findExpectedExceptions(m_annotationFinder, testMethod.getMethod()); + final ITestClass testClass= testMethod.getTestClass(); + final List<ITestResult> result = Lists.newArrayList(); + final FailureContext failure = new FailureContext(); + final ITestNGMethod[] beforeMethods = filterMethods(testClass, testClass.getBeforeTestMethods(), CAN_RUN_FROM_CLASS); + final ITestNGMethod[] afterMethods = filterMethods(testClass, testClass.getAfterTestMethods(), CAN_RUN_FROM_CLASS); while(invocationCount-- > 0) { - boolean okToProceed = checkDependencies(testMethod, allTestMethods); - - if (!okToProceed) { - // - // Not okToProceed. Test is being skipped - // - ITestResult testResult = new TestResult(testClass, null /* instance */, - testMethod, - null /* cause */, - start, - System.currentTimeMillis(), - m_testContext); - String missingGroup = testMethod.getMissingGroup(); - if (missingGroup != null) { - testResult.setThrowable(new Throwable("Method " + testMethod - + " depends on nonexistent group \"" + missingGroup + "\"")); - } - - testResult.setStatus(ITestResult.SKIP); - result.add(testResult); - m_notifier.addSkippedTest(testMethod, testResult); - runTestListeners(testResult); - return result; - } - - // - // If threadPoolSize specified, run this method in its own pool thread. - // - Map<String, String> parameters = - testMethod.findMethodParameters(testContext.getCurrentXmlTest()); - if (testMethod.getThreadPoolSize() > 1 && testMethod.getInvocationCount() > 1) { - return invokePooledTestMethods(testMethod, allTestMethods, suite, - parameters, groupMethods, testContext); + if(false) { + // Prevent code formatting } // // No threads, regular invocation // else { - ITestNGMethod[] beforeMethods = filterMethods(testClass, testClass.getBeforeTestMethods(), - CAN_RUN_FROM_CLASS); - ITestNGMethod[] afterMethods = filterMethods(testClass, testClass.getAfterTestMethods(), - CAN_RUN_FROM_CLASS); + // Used in catch statement + long start = System.currentTimeMillis(); Map<String, String> allParameterNames = Maps.newHashMap(); ParameterBag bag = createParameters(testMethod, - parameters, allParameterNames, null, suite, testContext, instances[0], - null); + parameters, allParameterNames, suite, testContext, instance); if (bag.hasErrors()) { - failureCount = handleInvocationResults(testMethod, - bag.errorResults, null, failureCount, expectedExceptionHolder, true, - true /* collect results */); - ITestResult tr = registerSkippedTestResult(testMethod, instances[0], start, - bag.errorResults.get(0).getThrowable()); + final ITestResult tr = bag.errorResult; + tr.setStatus(ITestResult.SKIP); + runTestListeners(tr); + m_notifier.addSkippedTest(testMethod, tr); result.add(tr); continue; } @@ -1205,10 +1163,10 @@ public class Invoker implements IInvoker { TestMethodWithDataProviderMethodWorker w = new TestMethodWithDataProviderMethodWorker(this, testMethod, parametersIndex, - parameterValues, instances, suite, parameters, testClass, + parameterValues, instance, suite, parameters, testClass, beforeMethods, afterMethods, groupMethods, expectedExceptionHolder, testContext, m_skipFailedInvocationCounts, - invocationCount, failureCount, m_notifier); + invocationCount, failure.count, m_notifier); workers.add(w); // testng387: increment the param index in the bag. parametersIndex++; @@ -1228,34 +1186,28 @@ public class Invoker implements IInvoker { List<ITestResult> tmpResults = Lists.newArrayList(); try { - tmpResults.addAll(invokeTestMethod(instances, - testMethod, - parameterValues, - parametersIndex, - suite, - parameters, - testClass, - beforeMethods, - afterMethods, - groupMethods)); + tmpResults.add(invokeTestMethod(instance, + testMethod, + parameterValues, + parametersIndex, + suite, + parameters, + testClass, + beforeMethods, + afterMethods, + groupMethods, failure)); } finally { - List<Object> failedInstances = Lists.newArrayList(); - - failureCount = handleInvocationResults(testMethod, tmpResults, - failedInstances, failureCount, expectedExceptionHolder, true, - false /* don't collect results */); - if (failedInstances.isEmpty()) { + if (failure.instances.isEmpty()) { result.addAll(tmpResults); } else { - for (int i = 0; i < failedInstances.size(); i++) { + for (Object failedInstance : failure.instances) { List<ITestResult> retryResults = Lists.newArrayList(); - failureCount = - retryFailed(failedInstances.toArray(), - i, testMethod, suite, testClass, beforeMethods, + failure.count = retryFailed( + failedInstance, testMethod, suite, testClass, beforeMethods, afterMethods, groupMethods, retryResults, - failureCount, expectedExceptionHolder, + failure.count, expectedExceptionHolder, testContext, parameters, parametersIndex); result.addAll(retryResults); } @@ -1265,11 +1217,11 @@ public class Invoker implements IInvoker { // If we have a failure, skip all the // other invocationCounts // - if (failureCount > 0 + if (failure.count > 0 && (m_skipFailedInvocationCounts || testMethod.skipFailedInvocations())) { while (invocationCount-- > 0) { - result.add(registerSkippedTestResult(testMethod, instances[0], start, null)); + result.add(registerSkippedTestResult(testMethod, instance, System.currentTimeMillis(), null)); } break; } @@ -1281,7 +1233,7 @@ public class Invoker implements IInvoker { catch (Throwable cause) { ITestResult r = new TestResult(testMethod.getTestClass(), - instances[0], + instance, testMethod, cause, start, @@ -1390,14 +1342,13 @@ public class Invoker implements IInvoker { testMethod.getMethod(), testContext, testResult), suite, m_annotationFinder, - fedInstance), - null /* TestResult */); + fedInstance)); } // catch(TestNGException ex) { // throw ex; // } catch(Throwable cause) { - return new ParameterBag(null /* ParameterHolder */, + return new ParameterBag( new TestResult( testMethod.getTestClass(), instance, @@ -1413,7 +1364,6 @@ public class Invoker implements IInvoker { * Invokes a method that has a specified threadPoolSize. */ private List<ITestResult> invokePooledTestMethods(ITestNGMethod testMethod, - ITestNGMethod[] allTestMethods, XmlSuite suite, Map<String, String> parameters, ConfigurationGroupMethods groupMethods, @@ -1436,38 +1386,42 @@ public class Invoker implements IInvoker { mi, suite, parameters, - allTestMethods, testContext)); } return runWorkers(testMethod, workers, testMethod.getThreadPoolSize(), groupMethods, suite, parameters); } + static class FailureContext { + int count = 0; + List<Object> instances = Lists.newArrayList(); + } + /** * @param testMethod * @param result - * @param failureCount * @param expectedExceptionsHolder + * @param failure * @return */ - int handleInvocationResults(ITestNGMethod testMethod, - List<ITestResult> result, - List<Object> failedInstances, - int failureCount, - ExpectedExceptionsHolder expectedExceptionsHolder, - boolean triggerListeners, - boolean collectResults) + void handleInvocationResults(ITestNGMethod testMethod, + List<ITestResult> result, + ExpectedExceptionsHolder expectedExceptionsHolder, + boolean triggerListeners, + boolean collectResults, + FailureContext failure) { // // Go through all the results and create a TestResult for each of them // List<ITestResult> resultsToRetry = Lists.newArrayList(); - for (int i = 0; i < result.size(); i++) { - ITestResult testResult = result.get(i); + for (ITestResult testResult : result) { Throwable ite= testResult.getThrowable(); int status= testResult.getStatus(); + boolean handled = false; + // Exception thrown? if (ite != null) { @@ -1484,24 +1438,18 @@ public class Invoker implements IInvoker { " but got \"" + ite.getMessage() + "\"", ite)); status= ITestResult.FAILURE; } - } else if (SkipException.class.isAssignableFrom(ite.getClass())){ - SkipException skipEx= (SkipException) ite; - if(skipEx.isSkip()) { - status = ITestResult.SKIP; - } - else { - handleException(ite, testMethod, testResult, failureCount++); - status = ITestResult.FAILURE; - } - } else if (ite != null && expectedExceptionsHolder != null) { + } else if (isSkipExceptionAndSkip(ite)){ + status = ITestResult.SKIP; + } else if (expectedExceptionsHolder != null) { testResult.setThrowable( - new TestException("Expected exception " - + expectedExceptionsHolder.expectedClasses[0].getName() - + " but got " + ite, ite)); + new TestException("Expected exception of " + + getExpectedExceptionsPluralize(expectedExceptionsHolder) + + " but got " + ite, ite)); status= ITestResult.FAILURE; } else { - handleException(ite, testMethod, testResult, failureCount++); - status= testResult.getStatus(); + handleException(ite, testMethod, testResult, failure.count++); + handled = true; + status = testResult.getStatus(); } } @@ -1511,53 +1459,52 @@ public class Invoker implements IInvoker { if (classes != null && classes.length > 0) { testResult.setThrowable( new TestException("Method " + testMethod + " should have thrown an exception of " - + expectedExceptionsHolder.expectedClasses[0])); + + getExpectedExceptionsPluralize(expectedExceptionsHolder))); status= ITestResult.FAILURE; } } testResult.setStatus(status); - boolean retry = false; + if (status == ITestResult.FAILURE && !handled) { + handleException(ite, testMethod, testResult, failure.count++); + status = testResult.getStatus(); + } - if (testResult.getStatus() == ITestResult.FAILURE) { + if (status == ITestResult.FAILURE) { IRetryAnalyzer retryAnalyzer = testMethod.getRetryAnalyzer(); - if (retryAnalyzer != null && failedInstances != null) { - retry = retryAnalyzer.retry(testResult); - } - - if (retry) { + if (retryAnalyzer != null && failure.instances != null && retryAnalyzer.retry(testResult)) { resultsToRetry.add(testResult); - if (failedInstances != null) { - failedInstances.add(testResult.getInstance()); - } + failure.instances.add(testResult.getInstance()); } } if (collectResults) { // Collect the results - if(ITestResult.SUCCESS == status) { - m_notifier.addPassedTest(testMethod, testResult); - } - else if(ITestResult.SKIP == status) { - m_notifier.addSkippedTest(testMethod, testResult); - } - else if(ITestResult.FAILURE == status) { - m_notifier.addFailedTest(testMethod, testResult); - } - else if(ITestResult.SUCCESS_PERCENTAGE_FAILURE == status) { - m_notifier.addFailedButWithinSuccessPercentageTest(testMethod, testResult); - } - else { - assert false : "UNKNOWN STATUS:" + status; - } + collectResults(testMethod, Collections.singleton(testResult)); // if (triggerListeners && status != ITestResult.SUCCESS) { // runTestListeners(testResult); // } } } // for results - return removeResultsToRetryFromResult(resultsToRetry, result, failureCount); + removeResultsToRetryFromResult(resultsToRetry, result, failure); + } + + private String getExpectedExceptionsPluralize(final ExpectedExceptionsHolder holder) { + StringBuilder sb = new StringBuilder(); + if (holder.expectedClasses.length > 1) { + sb.append("any of types "); + sb.append(Arrays.toString(holder.expectedClasses)); + } else { + sb.append("type "); + sb.append(holder.expectedClasses[0]); + } + return sb.toString(); + } + + private boolean isSkipExceptionAndSkip(Throwable ite) { + return SkipException.class.isAssignableFrom(ite.getClass()) && ((SkipException) ite).isSkip(); } /** @@ -1569,23 +1516,19 @@ public class Invoker implements IInvoker { if (".*".equals(messageRegExp)) { return true; } else { - if (ite.getMessage() == null) { - return false; - } else { - return Pattern.matches(messageRegExp, ite.getMessage()); - } + final String message = ite.getMessage(); + return message != null && Pattern.matches(messageRegExp, message); } } - private int removeResultsToRetryFromResult(List<ITestResult> resultsToRetry, - List<ITestResult> result, int failureCount) { + private void removeResultsToRetryFromResult(List<ITestResult> resultsToRetry, + List<ITestResult> result, FailureContext failure) { if (resultsToRetry != null) { for (ITestResult res : resultsToRetry) { result.remove(res); - failureCount--; + failure.count--; } } - return failureCount; } /** @@ -1640,51 +1583,55 @@ public class Invoker implements IInvoker { * Checks to see of the test method has certain dependencies that prevents * TestNG from executing it * @param testMethod test method being checked for - * @param testClass - * @return dependencies have been run successfully + * @return error message or null if dependencies have been run successfully */ - private boolean checkDependencies(ITestNGMethod testMethod, - ITestNGMethod[] allTestMethods) + private String checkDependencies(ITestNGMethod testMethod, + ITestNGMethod[] allTestMethods) { - boolean result = true; - // If this method is marked alwaysRun, no need to check for its dependencies if (testMethod.isAlwaysRun()) { - return true; + return null; } // Any missing group? if (testMethod.getMissingGroup() != null - && !testMethod.ignoreMissingDependencies()) { - return false; + && !testMethod.ignoreMissingDependencies()) { + return "Method " + testMethod + " depends on nonexistent group \"" + testMethod.getMissingGroup() + "\""; } // If this method depends on groups, collect all the methods that // belong to these groups and make sure they have been run successfully - if (dependsOnGroups(testMethod)) { - String[] groupsDependedUpon = testMethod.getGroupsDependedUpon(); - + final String[] groups = testMethod.getGroupsDependedUpon(); + if (null != groups && groups.length > 0) { // Get all the methods that belong to the group depended upon - for (String element : groupsDependedUpon) { + for (String element : groups) { ITestNGMethod[] methods = - MethodGroupsHelper.findMethodsThatBelongToGroup(testMethod, - m_testContext.getAllTestMethods(), - element); - - result = result && haveBeenRunSuccessfully(testMethod, methods); + MethodGroupsHelper.findMethodsThatBelongToGroup(testMethod, + m_testContext.getAllTestMethods(), + element); + if (methods.length == 0 && !testMethod.ignoreMissingDependencies()) { + // Group is missing + return "Method " + testMethod + " depends on nonexistent group \"" + element + "\""; + } + if (!haveBeenRunSuccessfully(testMethod, methods)) { + return "Method " + testMethod + + " depends on not successfully finished methods in group \"" + element + "\""; + } } } // depends on groups // If this method depends on other methods, make sure all these other // methods have been run successfully - if (result && dependsOnMethods(testMethod)) { + if (dependsOnMethods(testMethod)) { ITestNGMethod[] methods = - MethodHelper.findDependedUponMethods(testMethod, allTestMethods); + MethodHelper.findDependedUponMethods(testMethod, allTestMethods); - result = result && haveBeenRunSuccessfully(testMethod, methods); + if (!haveBeenRunSuccessfully(testMethod, methods)) { + return "Method " + testMethod + " depends on not successfully finished methods"; + } } - return result; + return null; } /** @@ -1693,13 +1640,12 @@ public class Invoker implements IInvoker { private Set<ITestResult> keepSameInstances(ITestNGMethod method, Set<ITestResult> results) { Set<ITestResult> result = Sets.newHashSet(); for (ITestResult r : results) { - for (Object o : method.getInstances()) { + final Object o = method.getInstance(); // Keep this instance if 1) It's on a different class or 2) It's on the same class // and on the same instance Object instance = r.getInstance() != null - ? r.getInstance() : r.getMethod().getInstances()[0]; + ? r.getInstance() : r.getMethod().getInstance(); if (r.getTestClass() != method.getTestClass() || instance == o) result.add(r); - } } return result; } @@ -1750,7 +1696,9 @@ public class Invoker implements IInvoker { ITestNGMethod testMethod, ITestResult testResult, int failureCount) { - testResult.setThrowable(throwable); + if (throwable != null) { + testResult.setThrowable(throwable); + } int successPercentage= testMethod.getSuccessPercentage(); int invocationCount= testMethod.getInvocationCount(); float numberOfTestsThatCanFail= ((100 - successPercentage) * invocationCount) / 100f; @@ -1766,13 +1714,13 @@ public class Invoker implements IInvoker { /** * @param ite The exception that was just thrown - * @param expectedExceptions The list of expected exceptions for this + * @param exceptionHolder Expected exceptions holder for this * test method * @return true if the exception that was just thrown is part of the * expected exceptions */ private boolean isExpectedException(Throwable ite, ExpectedExceptionsHolder exceptionHolder) { - if (exceptionHolder == null) { + if (exceptionHolder == null || exceptionHolder.expectedClasses == null) { return false; } @@ -1834,21 +1782,11 @@ public class Invoker implements IInvoker { } /** - * @return true if this method depends on certain groups. - */ - private boolean dependsOnGroups(ITestNGMethod tm) { - String[] groups = tm.getGroupsDependedUpon(); - boolean result = (null != groups) && (groups.length > 0); - return result; - } - - /** - * @return true if this method depends on certain groups. + * @return true if this method depends on certain methods. */ private boolean dependsOnMethods(ITestNGMethod tm) { String[] methods = tm.getMethodsDependedUpon(); - boolean result = (null != methods) && (methods.length > 0); - return result; + return null != methods && methods.length > 0; } private void runConfigurationListeners(ITestResult tr, boolean before) { @@ -1917,22 +1855,25 @@ public class Invoker implements IInvoker { } /** - * This class holds a {@code ParameterHolder} and in case of an error, a non-null + * This class holds a {@code ParameterHolder} or in case of an error, a non-null * {@code TestResult} containing the cause */ private static class ParameterBag { final ParameterHolder parameterHolder; - final List<ITestResult> errorResults = Lists.newArrayList(); + final ITestResult errorResult; - public ParameterBag(ParameterHolder params, TestResult tr) { - parameterHolder = params; - if (tr != null) { - errorResults.add(tr); - } + public ParameterBag(ParameterHolder parameterHolder) { + this.parameterHolder = parameterHolder; + this.errorResult = null; + } + + public ParameterBag(ITestResult errorResult) { + this.parameterHolder = null; + this.errorResult = errorResult; } public boolean hasErrors() { - return !errorResults.isEmpty(); + return errorResult != null; } } diff --git a/src/main/java/org/testng/internal/MethodGroupsHelper.java b/src/main/java/org/testng/internal/MethodGroupsHelper.java index 11cb668..622a122 100644 --- a/src/main/java/org/testng/internal/MethodGroupsHelper.java +++ b/src/main/java/org/testng/internal/MethodGroupsHelper.java @@ -254,34 +254,57 @@ public class MethodGroupsHelper { ITestNGMethod method, ITestNGMethod[] methods, String groupRegexp) { - boolean foundGroup = false; - List<ITestNGMethod> vResult = Lists.newArrayList(); - Pattern groupPattern = PATTERN_CACHE.get(groupRegexp); - if (groupPattern == null) { - groupPattern = Pattern.compile(groupRegexp); - PATTERN_CACHE.put(groupRegexp, groupPattern); + ITestNGMethod[] found = findMethodsThatBelongToGroup(methods, groupRegexp); + + if (found.length == 0) { + method.setMissingGroup(groupRegexp); } + + return found; + } + + /** + * @param methods list of methods to search + * @param groupRegexp regex representing the group + * + * @return all the methods that belong to the group specified by the regular + * expression groupRegExp. methods[] is the list of all the methods we + * are choosing from. + */ + protected static ITestNGMethod[] findMethodsThatBelongToGroup(ITestNGMethod[] methods, String groupRegexp) + { + List<ITestNGMethod> vResult = Lists.newArrayList(); + final Pattern pattern = getPattern(groupRegexp); for (ITestNGMethod tm : methods) { String[] groups = tm.getGroups(); for (String group : groups) { - Pair<String, String> cacheKey = Pair.create(groupRegexp, group); - Boolean match = MATCH_CACHE.get(cacheKey); - if (match == null) { - match = groupPattern.matcher(group).matches(); - MATCH_CACHE.put(cacheKey, match); - } + Boolean match = isMatch(pattern, group); if (match) { vResult.add(tm); - foundGroup = true; } } } - if (!foundGroup) { - method.setMissingGroup(groupRegexp); + return vResult.toArray(new ITestNGMethod[vResult.size()]); + } + + private static Boolean isMatch(Pattern pattern, String group) { + Pair<String, String> cacheKey = Pair.create(pattern.pattern(), group); + Boolean match = MATCH_CACHE.get(cacheKey); + if (match == null) { + match = pattern.matcher(group).matches(); + MATCH_CACHE.put(cacheKey, match); } + return match; + } - return vResult.toArray(new ITestNGMethod[vResult.size()]); + private static Pattern getPattern(String groupRegexp) { + Pattern groupPattern = PATTERN_CACHE.get(groupRegexp); + if (groupPattern == null) { + groupPattern = Pattern.compile(groupRegexp); + PATTERN_CACHE.put(groupRegexp, groupPattern); + } + return groupPattern; } diff --git a/src/main/java/org/testng/internal/MethodInvocationHelper.java b/src/main/java/org/testng/internal/MethodInvocationHelper.java index 79b92e5..f5821f8 100644 --- a/src/main/java/org/testng/internal/MethodInvocationHelper.java +++ b/src/main/java/org/testng/internal/MethodInvocationHelper.java @@ -1,7 +1,9 @@ package org.testng.internal; +import org.testng.IConfigurable; import org.testng.IConfigureCallBack; import org.testng.IHookCallBack; +import org.testng.IHookable; import org.testng.ITestContext; import org.testng.ITestNGMethod; import org.testng.ITestResult; @@ -36,7 +38,6 @@ public class MethodInvocationHelper { protected static Object invokeMethod(Method thisMethod, Object instance, Object[] parameters) throws InvocationTargetException, IllegalAccessException { - Object result = null; Utils.checkInstanceOrStatic(instance, thisMethod); // TESTNG-326, allow IObjectFactory to load from non-standard classloader @@ -87,7 +88,7 @@ public class MethodInvocationHelper { protected static Iterator<Object[]> invokeDataProvider(Object instance, Method dataProvider, ITestNGMethod method, ITestContext testContext, Object fedInstance, IAnnotationFinder annotationFinder) { - Iterator<Object[]> result = null; + Iterator<Object[]> result; final ConstructorOrMethod com = method.getConstructorOrMethod(); // If it returns an Object[][], convert it to an Iterable<Object[]> @@ -149,7 +150,7 @@ public class MethodInvocationHelper { method.setParameterInvocationCount(oResult.length); result = MethodHelper.createArrayIterator(oResult); } else if (Iterator.class.isAssignableFrom(returnType)) { - // Already an Iterable<Object[]>, assign it directly + // Already an Iterator<Object[]>, assign it directly result = (Iterator<Object[]>) invokeMethod(dataProvider, instance, parameters); } else { throw new TestNGException("Data Provider " + dataProvider + " must return" @@ -188,9 +189,8 @@ public class MethodInvocationHelper { * <tt>thisMethod</code> results in an exception */ protected static void invokeHookable(final Object testInstance, final Object[] parameters, - Object hookableInstance, final Method thisMethod, TestResult testResult) throws Throwable { - Method runMethod = hookableInstance.getClass().getMethod("run", - new Class[] { IHookCallBack.class, ITestResult.class }); + final IHookable hookable, final Method thisMethod, + final TestResult testResult) throws Throwable { final Throwable[] error = new Throwable[1]; IHookCallBack callback = new IHookCallBack() { @@ -209,7 +209,7 @@ public class MethodInvocationHelper { return parameters; } }; - runMethod.invoke(hookableInstance, new Object[] { callback, testResult }); + hookable.run(callback, testResult); if (error[0] != null) { throw error[0]; } @@ -248,7 +248,7 @@ public class MethodInvocationHelper { private static void invokeWithTimeoutWithNewExecutor(ITestNGMethod tm, Object instance, Object[] parameterValues, ITestResult testResult) throws InterruptedException, ThreadExecutionException { - IExecutor exec = ThreadUtil.createExecutor(1, tm.getMethod().getName()); + IExecutor exec = ThreadUtil.createExecutor(1, tm.getMethodName()); InvokeMethodRunnable imr = new InvokeMethodRunnable(tm, instance, parameterValues); IFutureResult future = exec.submitRunnable(imr); @@ -265,7 +265,7 @@ public class MethodInvocationHelper { testResult.setThrowable(exception); testResult.setStatus(ITestResult.FAILURE); } else { - Utils.log("Invoker " + Thread.currentThread().hashCode(), 3, "Method " + tm.getMethod() + Utils.log("Invoker " + Thread.currentThread().hashCode(), 3, "Method " + tm.getMethodName() + " completed within the time-out " + tm.getTimeOut()); // We don't need the result from the future but invoking get() on it @@ -279,10 +279,8 @@ public class MethodInvocationHelper { } protected static void invokeConfigurable(final Object instance, final Object[] parameters, - Object configurableInstance, final Method thisMethod, ITestResult testResult) - throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, Throwable { - Method runMethod = configurableInstance.getClass().getMethod("run", - new Class[] { IConfigureCallBack.class, ITestResult.class }); + final IConfigurable configurableInstance, final Method thisMethod, + final ITestResult testResult) throws Throwable { final Throwable[] error = new Throwable[1]; IConfigureCallBack callback = new IConfigureCallBack() { @@ -301,10 +299,10 @@ public class MethodInvocationHelper { return parameters; } }; - runMethod.invoke(configurableInstance, new Object[] { callback, testResult }); + configurableInstance.run(callback, testResult); if (error[0] != null) { throw error[0]; } } -} \ No newline at end of file +} diff --git a/src/main/java/org/testng/internal/Parameters.java b/src/main/java/org/testng/internal/Parameters.java index 3708011..4fa7c91 100755 --- a/src/main/java/org/testng/internal/Parameters.java +++ b/src/main/java/org/testng/internal/Parameters.java @@ -1,5 +1,15 @@ package org.testng.internal; +import java.lang.reflect.Constructor; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.Collections; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; + import org.testng.ITestContext; import org.testng.ITestNGMethod; import org.testng.ITestResult; @@ -19,16 +29,6 @@ import org.testng.util.Strings; import org.testng.xml.XmlSuite; import org.testng.xml.XmlTest; -import java.lang.reflect.Constructor; -import java.lang.reflect.Method; -import java.lang.reflect.Modifier; -import java.util.Collections; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Set; - /** * Methods that bind parameters declared in testng.xml to actual values * used to invoke methods. @@ -220,28 +220,28 @@ public class Parameters { result = value; } else if(type == int.class || type == Integer.class) { - result = Integer.valueOf(Integer.parseInt(value)); + result = Integer.parseInt(value); } else if(type == boolean.class || type == Boolean.class) { result = Boolean.valueOf(value); } else if(type == byte.class || type == Byte.class) { - result = Byte.valueOf(Byte.parseByte(value)); + result = Byte.parseByte(value); } else if(type == char.class || type == Character.class) { - result = Character.valueOf(value.charAt(0)); + result = value.charAt(0); } else if(type == double.class || type == Double.class) { - result = Double.valueOf(Double.parseDouble(value)); + result = Double.parseDouble(value); } else if(type == float.class || type == Float.class) { - result = Float.valueOf(Float.parseFloat(value)); + result = Float.parseFloat(value); } else if(type == long.class || type == Long.class) { - result = Long.valueOf(Long.parseLong(value)); + result = Long.parseLong(value); } else if(type == short.class || type == Short.class) { - result = Short.valueOf(Short.parseShort(value)); + result = Short.parseShort(value); } else if (type.isEnum()) { result = Enum.valueOf(type, value); @@ -282,7 +282,7 @@ public class Parameters { */ private static IDataProvidable findDataProviderInfo(Class clazz, ConstructorOrMethod m, IAnnotationFinder finder) { - IDataProvidable result = null; + IDataProvidable result; if (m.getMethod() != null) { // @@ -325,8 +325,7 @@ public class Parameters { } for (Method m : ClassHelper.getAvailableMethods(cls)) { - IDataProviderAnnotation dp = (IDataProviderAnnotation) - finder.findAnnotation(m, IDataProviderAnnotation.class); + IDataProviderAnnotation dp = finder.findAnnotation(m, IDataProviderAnnotation.class); if (null != dp && name.equals(getDataProviderName(dp, m))) { if (shouldBeStatic && (m.getModifiers() & Modifier.STATIC) == 0) { throw new TestNGException("DataProvider should be static: " + m); @@ -352,11 +351,11 @@ public class Parameters { { List<Object> result = Lists.newArrayList(); - Object[] extraParameters = new Object[0]; + Object[] extraParameters; // // Try to find an @Parameters annotation // - IParametersAnnotation annotation = (IParametersAnnotation) finder.findAnnotation(m, IParametersAnnotation.class); + IParametersAnnotation annotation = finder.findAnnotation(m, IParametersAnnotation.class); Class<?>[] types = m.getParameterTypes(); if(null != annotation) { String[] parameterNames = annotation.getValue(); @@ -383,9 +382,7 @@ public class Parameters { // // Add the extra parameters we found // - for (Object p : extraParameters) { - result.add(p); - } + Collections.addAll(result, extraParameters); // If the method declared an Object[] parameter and we have parameter values, inject them for (int i = 0; i < types.length; i++) { @@ -413,7 +410,7 @@ public class Parameters { Object fedInstance) { ParameterHolder result; - Iterator<Object[]> parameters = null; + Iterator<Object[]> parameters; /* * Do we have a @DataProvider? If yes, then we have several @@ -462,8 +459,7 @@ public class Parameters { // Turn it into an Iterable parameters = MethodHelper.createArrayIterator(allParameterValuesArray); - result = new ParameterHolder(parameters, ParameterOrigin.ORIGIN_XML, - dataProviderHolder); + result = new ParameterHolder(parameters, ParameterOrigin.ORIGIN_XML, null); } return result; diff --git a/src/main/java/org/testng/internal/TestMethodWithDataProviderMethodWorker.java b/src/main/java/org/testng/internal/TestMethodWithDataProviderMethodWorker.java index 8ba02f3..96be14a 100755 --- a/src/main/java/org/testng/internal/TestMethodWithDataProviderMethodWorker.java +++ b/src/main/java/org/testng/internal/TestMethodWithDataProviderMethodWorker.java @@ -15,7 +15,7 @@ public class TestMethodWithDataProviderMethodWorker implements Callable<List<ITe private ITestNGMethod m_testMethod; private Object[] m_parameterValues; - private Object[] m_instances; + private Object m_instance; private XmlSuite m_xmlSuite; private Map<String, String> m_parameters; private ITestClass m_testClass; @@ -35,7 +35,7 @@ public class TestMethodWithDataProviderMethodWorker implements Callable<List<ITe public TestMethodWithDataProviderMethodWorker(Invoker invoker, ITestNGMethod testMethod, int parameterIndex, - Object[] parameterValues, Object[] instances, XmlSuite suite, + Object[] parameterValues, Object instance, XmlSuite suite, Map<String, String> parameters, ITestClass testClass, ITestNGMethod[] beforeMethods, ITestNGMethod[] afterMethods, ConfigurationGroupMethods groupMethods, ExpectedExceptionsHolder expectedExceptionHolder, @@ -45,7 +45,7 @@ public class TestMethodWithDataProviderMethodWorker implements Callable<List<ITe m_testMethod = testMethod; m_parameterIndex = parameterIndex; m_parameterValues = parameterValues; - m_instances = instances; + m_instance = instance; m_xmlSuite = suite; m_parameters = parameters; m_testClass = testClass; @@ -69,33 +69,32 @@ public class TestMethodWithDataProviderMethodWorker implements Callable<List<ITe List<ITestResult> tmpResults = Lists.newArrayList(); long start = System.currentTimeMillis(); + final Invoker.FailureContext failure = new Invoker.FailureContext(); + failure.count = m_failureCount; try { - tmpResults.addAll(m_invoker.invokeTestMethod(m_instances, - m_testMethod, - m_parameterValues, - m_parameterIndex, - m_xmlSuite, - m_parameters, - m_testClass, - m_beforeMethods, - m_afterMethods, - m_groupMethods)); + tmpResults.add(m_invoker.invokeTestMethod(m_instance, + m_testMethod, + m_parameterValues, + m_parameterIndex, + m_xmlSuite, + m_parameters, + m_testClass, + m_beforeMethods, + m_afterMethods, + m_groupMethods, + failure)); } finally { - List<Object> failedInstances = Lists.newArrayList(); - - m_failureCount = m_invoker.handleInvocationResults(m_testMethod, tmpResults, - failedInstances, m_failureCount, m_expectedExceptionHolder, true, - false /* don't collect results */); - if (failedInstances.isEmpty()) { + m_failureCount = failure.count; + if (failure.instances.isEmpty()) { m_testResults.addAll(tmpResults); } else { - for (int i = 0; i < failedInstances.size(); i++) { + for (Object instance : failure.instances) { List<ITestResult> retryResults = Lists.newArrayList(); m_failureCount = - m_invoker.retryFailed(failedInstances.toArray(), - i, m_testMethod, m_xmlSuite, m_testClass, m_beforeMethods, + m_invoker.retryFailed( + instance, m_testMethod, m_xmlSuite, m_testClass, m_beforeMethods, m_afterMethods, m_groupMethods, retryResults, m_failureCount, m_expectedExceptionHolder, m_testContext, m_parameters, m_parameterIndex); @@ -118,7 +117,7 @@ public class TestMethodWithDataProviderMethodWorker implements Callable<List<ITe while (m_invocationCount-- > 0) { ITestResult r = new TestResult(m_testMethod.getTestClass(), - m_instances[0], + m_instance, m_testMethod, null, start, diff --git a/src/main/java/org/testng/internal/TestMethodWorker.java b/src/main/java/org/testng/internal/TestMethodWorker.java index d251264..cb93beb 100644 --- a/src/main/java/org/testng/internal/TestMethodWorker.java +++ b/src/main/java/org/testng/internal/TestMethodWorker.java @@ -36,7 +36,6 @@ public class TestMethodWorker implements IWorker<ITestNGMethod> { private final IInvoker m_invoker; private final Map<String, String> m_parameters; private final XmlSuite m_suite; - private final ITestNGMethod[] m_allTestMethods; private List<ITestResult> m_testResults = Lists.newArrayList(); private final ConfigurationGroupMethods m_groupMethods; private final ClassMethodMap m_classMethodMap; @@ -46,7 +45,6 @@ public class TestMethodWorker implements IWorker<ITestNGMethod> { IMethodInstance[] testMethods, XmlSuite suite, Map<String, String> parameters, - ITestNGMethod[] allTestMethods, ConfigurationGroupMethods groupMethods, ClassMethodMap classMethodMap, ITestContext testContext) @@ -55,7 +53,6 @@ public class TestMethodWorker implements IWorker<ITestNGMethod> { m_methodInstances = testMethods; m_suite = suite; m_parameters = parameters; - m_allTestMethods = allTestMethods; m_groupMethods = groupMethods; m_classMethodMap = classMethodMap; m_testContext = testContext; @@ -108,7 +105,7 @@ public class TestMethodWorker implements IWorker<ITestNGMethod> { // Invoke test method try { - invokeTestMethods(testMethod, testMthdInst.getInstances(), m_testContext); + invokeTestMethods(testMethod, testMthdInst.getInstance(), m_testContext); } finally { invokeAfterClassMethods(testClass, testMthdInst); @@ -116,7 +113,7 @@ public class TestMethodWorker implements IWorker<ITestNGMethod> { } } - protected void invokeTestMethods(ITestNGMethod tm, Object[] instances, + protected void invokeTestMethods(ITestNGMethod tm, Object instance, ITestContext testContext) { // Potential bug here: we look up the method index of tm among all @@ -126,12 +123,10 @@ public class TestMethodWorker implements IWorker<ITestNGMethod> { // more efficient) List<ITestResult> testResults = m_invoker.invokeTestMethods(tm, - m_allTestMethods, - indexOf(tm, m_allTestMethods), m_suite, m_parameters, m_groupMethods, - instances, + instance, testContext); if (testResults != null) { @@ -288,16 +283,14 @@ class SingleTestMethodWorker extends TestMethodWorker { MethodInstance testMethod, XmlSuite suite, Map<String, String> parameters, - ITestNGMethod[] allTestMethods, ITestContext testContext) { super(invoker, new MethodInstance[] {testMethod}, suite, parameters, - allTestMethods, EMPTY_GROUP_METHODS, null, testContext); } -} \ No newline at end of file +} diff --git a/src/main/java/org/testng/internal/annotations/JDK15TagFactory.java b/src/main/java/org/testng/internal/annotations/JDK15TagFactory.java index 2773460..5d4e6b3 100755 --- a/src/main/java/org/testng/internal/annotations/JDK15TagFactory.java +++ b/src/main/java/org/testng/internal/annotations/JDK15TagFactory.java @@ -2,7 +2,9 @@ package org.testng.internal.annotations; import java.lang.annotation.Annotation; import java.lang.reflect.Method; -import java.util.Map; +import java.util.HashSet; +import java.util.List; +import java.util.Set; import org.testng.IAnnotationTransformer; import org.testng.TestNGException; @@ -31,7 +33,7 @@ import org.testng.annotations.ITestAnnotation; import org.testng.annotations.Listeners; import org.testng.annotations.Parameters; import org.testng.annotations.Test; -import org.testng.collections.Maps; +import org.testng.collections.Lists; import org.testng.internal.Utils; /** @@ -417,15 +419,15 @@ public class JDK15TagFactory { } private String[] join(String[] strings, String[] strings2) { - Map<String, String> vResult = Maps.newHashMap(); - for (String s : strings) { - vResult.put(s, s); - } + List<String> result = Lists.newArrayList(strings); + Set<String> seen = new HashSet<String>(Lists.newArrayList(strings)); for (String s : strings2) { - vResult.put(s, s); + if (! seen.contains(s)) { + result.add(s); + } } - return vResult.keySet().toArray(new String[vResult.size()]); + return result.toArray(new String[result.size()]); } /** @@ -494,21 +496,20 @@ public class JDK15TagFactory { return new String[0]; } - Map<String, String> vResult = Maps.newHashMap(); + List<String> result = Lists.newArrayList(); while (cls != null && cls != Object.class) { Annotation annotation = cls.getAnnotation(annotationClass); if (annotation != null) { String[] g = (String[]) invokeMethod(annotation, methodName); for (String s : g) { - vResult.put(s, s); + result.add(s); } } cls = cls.getSuperclass(); } - String[] result = vResult.keySet().toArray(new String[vResult.size()]); - return result; + return result.toArray(new String[result.size()]); } private Object invokeMethod(Annotation test, String methodName) { diff --git a/src/main/java/org/testng/reporters/FileStringBuffer.java b/src/main/java/org/testng/reporters/FileStringBuffer.java index 80e774e..af2e98b 100644 --- a/src/main/java/org/testng/reporters/FileStringBuffer.java +++ b/src/main/java/org/testng/reporters/FileStringBuffer.java @@ -43,6 +43,9 @@ public class FileStringBuffer implements IBuffer { @Override public FileStringBuffer append(CharSequence s) { + if (s == null) { + throw new IllegalArgumentException("CharSequence (Argument 0 of FileStringBuffer#append) should not be null"); + } // m_sb.append(s); if (m_sb.length() > m_maxCharacters) { flushToFile(); @@ -64,6 +67,9 @@ public class FileStringBuffer implements IBuffer { @Override public void toWriter(Writer fw) { + if (fw == null) { + throw new IllegalArgumentException("Writer (Argument 0 of FileStringBuffer#toWriter) should not be null"); + } try { BufferedWriter bw = new BufferedWriter(fw); if (m_file == null) { diff --git a/src/main/java/org/testng/reporters/XMLStringBuffer.java b/src/main/java/org/testng/reporters/XMLStringBuffer.java index 092c10e..84046b4 100755 --- a/src/main/java/org/testng/reporters/XMLStringBuffer.java +++ b/src/main/java/org/testng/reporters/XMLStringBuffer.java @@ -14,8 +14,8 @@ import java.util.regex.Pattern; * @author <a href="mailto:[email protected]">Cedric Beust</a> Jul 21, 2003 */ public class XMLStringBuffer { - /** End of line */ - private static final String EOL = System.getProperty("line.separator"); + /** End of line, value of 'line.separator' system property or '\n' */ + private static final String EOL = System.getProperty("line.separator", "\n"); /** Tab space indent for XML document */ private static final String DEFAULT_INDENT_INCREMENT = " "; diff --git a/src/main/java/org/testng/xml/XmlSuite.java b/src/main/java/org/testng/xml/XmlSuite.java index 61612eb..bdcc3e5 100755 --- a/src/main/java/org/testng/xml/XmlSuite.java +++ b/src/main/java/org/testng/xml/XmlSuite.java @@ -1,7 +1,12 @@ package org.testng.xml; -import static org.testng.collections.CollectionUtils.hasElements; -import static org.testng.internal.Utils.isStringNotEmpty; +import java.io.Serializable; +import java.util.Collection; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Properties; +import java.util.Set; import org.testng.ITestObjectFactory; import org.testng.TestNG; @@ -12,13 +17,8 @@ import org.testng.xml.dom.OnElement; import org.testng.xml.dom.OnElementList; import org.testng.xml.dom.Tag; -import java.io.Serializable; -import java.util.Collection; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Properties; -import java.util.Set; +import static org.testng.collections.CollectionUtils.hasElements; +import static org.testng.internal.Utils.isStringNotEmpty; /** * This class describes the tag <suite> in testng.xml. @@ -439,6 +439,8 @@ public class XmlSuite implements Serializable, Cloneable { if(isStringNotEmpty(parallel) && !DEFAULT_PARALLEL.equals(parallel)) { p.setProperty("parallel", parallel); } + XmlUtils.setProperty(p, "group-by-instances", String.valueOf(getGroupByInstances()), + DEFAULT_GROUP_BY_INSTANCES.toString()); XmlUtils.setProperty(p, "configfailurepolicy", getConfigFailurePolicy(), DEFAULT_CONFIG_FAILURE_POLICY); XmlUtils.setProperty(p, "thread-count", String.valueOf(getThreadCount()), diff --git a/src/main/java/org/testng/xml/XmlTest.java b/src/main/java/org/testng/xml/XmlTest.java index 06abec1..cbc8c12 100755 --- a/src/main/java/org/testng/xml/XmlTest.java +++ b/src/main/java/org/testng/xml/XmlTest.java @@ -1,12 +1,5 @@ package org.testng.xml; -import org.testng.TestNG; -import org.testng.TestNGException; -import org.testng.collections.Lists; -import org.testng.collections.Maps; -import org.testng.reporters.XMLStringBuffer; -import org.testng.xml.dom.ParentSetter; - import java.io.Serializable; import java.util.ArrayList; import java.util.List; @@ -14,6 +7,13 @@ import java.util.Map; import java.util.Properties; import java.util.UUID; +import org.testng.TestNG; +import org.testng.TestNGException; +import org.testng.collections.Lists; +import org.testng.collections.Maps; +import org.testng.reporters.XMLStringBuffer; +import org.testng.xml.dom.ParentSetter; + /** * This class describes the tag <test> in testng.xml. * @@ -477,6 +477,10 @@ public class XmlTest implements Serializable, Cloneable { if (m_threadCount != -1) { p.setProperty("thread-count", Integer.toString(m_threadCount)); } + if (m_groupByInstances != null) { + XmlUtils.setProperty(p, "group-by-instances", String.valueOf(getGroupByInstances()), + XmlSuite.DEFAULT_GROUP_BY_INSTANCES.toString()); + } xsb.push("test", p); diff --git a/src/test/java/test/InvocationAndSuccessPercentageTest.java b/src/test/java/test/InvocationAndSuccessPercentageTest.java index ec0254f..56f4434 100644 --- a/src/test/java/test/InvocationAndSuccessPercentageTest.java +++ b/src/test/java/test/InvocationAndSuccessPercentageTest.java @@ -67,9 +67,9 @@ public class InvocationAndSuccessPercentageTest extends BaseTest { * 1 failed but within success percentage * 1 failed */ - @Test(enabled = false) + @Test public void successPercentageThatFails() { - addClass("test.sample.InvocationCountTest"); + addClass(test.sample.InvocationCountTest.class); addIncludedGroup("successPercentageThatFailsOnly"); run(); String[] passed = { diff --git a/src/test/java/test/dataprovider/DataProviderWithError.java b/src/test/java/test/dataprovider/DataProviderWithError.java new file mode 100644 index 0000000..a7b8c7f --- /dev/null +++ b/src/test/java/test/dataprovider/DataProviderWithError.java @@ -0,0 +1,25 @@ +package test.dataprovider; + +import org.testng.Assert; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +/** + * @author Vladislav.Rassokhin + */ +public class DataProviderWithError { + @Test(dataProvider = "Data", invocationCount = 2) + public void testShouldSkip() throws Exception { + Assert.fail(); + } + + @Test(dataProvider = "Data", invocationCount = 2, successPercentage = 10) + public void testShouldSkipEvenIfSuccessPercentage() throws Exception { + Assert.fail(); + } + + @DataProvider(name = "Data") + public static Object[][] Data() { + throw new RuntimeException("Fail"); + } +} diff --git a/src/test/java/test/dataprovider/FailingDataProviderTest.java b/src/test/java/test/dataprovider/FailingDataProviderTest.java index fff2564..ee31493 100644 --- a/src/test/java/test/dataprovider/FailingDataProviderTest.java +++ b/src/test/java/test/dataprovider/FailingDataProviderTest.java @@ -3,27 +3,32 @@ package test.dataprovider; import org.testng.Assert; import org.testng.TestListenerAdapter; import org.testng.TestNG; -import org.testng.TestNGException; import org.testng.annotations.Test; import test.SimpleBaseTest; public class FailingDataProviderTest extends SimpleBaseTest { - private void shouldSkipOne(Class cls, String message) { + private void shouldSkip(Class cls, String message, int expected) { TestNG testng = create(cls); TestListenerAdapter tla = new TestListenerAdapter(); testng.addListener(tla); testng.run(); - Assert.assertEquals(tla.getSkippedTests().size(), 1, message); + Assert.assertEquals(tla.getSkippedTests().size(), expected, message); } @Test(description = "TESTNG-142: Exceptions in DataProvider are not reported as failed test") public void failingDataProvider() { - shouldSkipOne(FailingDataProvider.class, "Test method should be marked as skipped"); + shouldSkip(FailingDataProvider.class, "Test method should be marked as skipped", 1); } @Test(description = "TESTNG-447: Abort when two data providers have the same name") public void duplicateDataProviders() { - shouldSkipOne(DuplicateDataProviderSampleTest.class, ""); + shouldSkip(DuplicateDataProviderSampleTest.class, "", 1); + } + + @Test + public void failingDataProviderAndInvocationCount() throws Exception { + shouldSkip(DataProviderWithError.class, + "Test should be skipped even if invocation counter and success percentage set", 4); } } diff --git a/src/test/java/test/testng106/TestNG106.java b/src/test/java/test/testng106/TestNG106.java index 92c883f..171463a 100644 --- a/src/test/java/test/testng106/TestNG106.java +++ b/src/test/java/test/testng106/TestNG106.java @@ -1,12 +1,13 @@ package test.testng106; +import java.util.Arrays; + import org.testng.Assert; import org.testng.TestNG; import org.testng.annotations.Test; import org.testng.xml.XmlSuite; -import test.SimpleBaseTest; -import java.util.Arrays; +import test.SimpleBaseTest; public class TestNG106 extends SimpleBaseTest { @Test @@ -18,7 +19,6 @@ public class TestNG106 extends SimpleBaseTest { createXmlTest(s, "myTest3", Test2.class.getName()); createXmlTest(s, "myTest-last", Test2.class.getName()); tng.setXmlSuites(Arrays.asList(s)); - tng.setVerbose(3); tng.run(); Assert.assertEquals(FailingSuiteFixture.s_invocations, 0, "@BeforeSuite has failed. All tests should be skipped."); } diff --git a/src/test/resources/testng-single.xml b/src/test/resources/testng-single.xml index 6898468..d144918 100644 --- a/src/test/resources/testng-single.xml +++ b/src/test/resources/testng-single.xml @@ -9,16 +9,11 @@ <parameter name="string" value="s"/> <groups> - <dependencies> - <group name="c" depends-on="a b" /> - <group name="z" depends-on="c" /> - </dependencies> </groups> <classes> - <class name="test.tmp.A"> - </class> - </classes> + <class name="test.mannotation.MAnnotationSampleTest" /> + </classes> </test> </suite> -- Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-java/testng.git _______________________________________________ pkg-java-commits mailing list [email protected] http://lists.alioth.debian.org/cgi-bin/mailman/listinfo/pkg-java-commits

