-
Notifications
You must be signed in to change notification settings - Fork 1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Tests are not running in correct order if parallel="classes" is used with tests having dependsOnGroup and Priority #2621
Comments
Kindly have a look. Above scenario is working fine:
|
Is it a duplicate of #2372? |
It is not duplicate as in #2372 we are talking about dependency only but in this we have dependency & priority both. |
@DarpanSinghal - Is this a problem only when running tests in eclipse or is this a problem when you run your tests using a build tool (Maven or Gradle). |
I checked with eclipse only taking testng 7.4 jar as an external jar. Along with it, tested using our Automation f/w code which is based on Gradle. |
@DarpanSinghal - Please verify this from a command line as well (using maven and/or gradle) because I would like to confirm if this problem is associated with the eclipse plugin (From your screenshots I gather that you are basing the conclusion based on the eclipse plugin output) and want to rule out a problem with core testng itself. So please try with maven/gradle and post back results. |
Hi @krmahadevan , Eclipse plugin was not used in this execution. I updated my previous comment. |
Kindly let me know when I can expect the fix. |
Below sample can be used to reproduce the problem Test classes import org.testng.annotations.Test;
public class TestClassSampleOne {
@Test(groups = {"g1"}, priority = 1)
public void t1() {
}
@Test(groups = {"g2"}, dependsOnGroups = "g1", priority = 3)
public void t2() {
}
@Test(groups = {"g2"}, dependsOnGroups = "g1", priority = 2)
public void t3() {
}
@Test(groups = {"g2"}, dependsOnGroups = "g1", priority = 5)
public void t4() {
}
@Test(groups = {"g2"}, priority = 4)
public void t5() {
}
} import org.testng.annotations.Test;
public class TestClassSampleTwo {
@Test(groups = {"g1"}, priority = 1)
public void t1() {
}
@Test(groups = {"g2"}, dependsOnGroups = "g1", priority = 3)
public void t2() {
}
@Test(groups = {"g2"}, dependsOnGroups = "g1", priority = 2)
public void t3() {
}
@Test(groups = {"g2"}, dependsOnGroups = "g1", priority = 5)
public void t4() {
}
@Test(groups = {"g2"}, priority = 4)
public void t5() {
}
} Listener that is used here import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import org.testng.IExecutionListener;
import org.testng.IInvokedMethod;
import org.testng.IInvokedMethodListener;
import org.testng.ITestResult;
import org.testng.internal.Version;
public class TestNarrator implements IInvokedMethodListener, IExecutionListener {
private final List<String> logs = Collections.synchronizedList(new ArrayList<>());
@Override
public void onExecutionStart() {
System.err.println("TestNG version : " + Version.VERSION);
}
@Override
public void onExecutionFinish() {
}
@Override
public void beforeInvocation(IInvokedMethod method, ITestResult testResult) {
int priority = method.getTestMethod().getPriority();
String[] groups = method.getTestMethod().getGroups();
String msg = String.format("{method=[%s],groups=%s,priority=[%d]}",
method.getTestMethod().getMethodName(),
Arrays.toString(groups),
priority
);
logs.add(msg);
}
@Override
public void afterInvocation(IInvokedMethod iInvokedMethod, ITestResult iTestResult) {
}
public List<String> getLogs() {
return logs;
}
} Test Runner import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
import org.testng.ITestNGListener;
import org.testng.TestNG;
import org.testng.annotations.Test;
import org.testng.xml.XmlClass;
import org.testng.xml.XmlGroups;
import org.testng.xml.XmlRun;
import org.testng.xml.XmlSuite;
import org.testng.xml.XmlSuite.ParallelMode;
import org.testng.xml.XmlTest;
public class TestCase {
@Test
public void runTestCase() {
XmlSuite xmlSuite = new XmlSuite();
xmlSuite.setParallel(ParallelMode.CLASSES);
xmlSuite.setThreadCount(2);
xmlSuite.setName("2621_suite");
XmlTest xmlTest = new XmlTest(xmlSuite);
xmlTest.setName("2621_test");
List<XmlClass> xmlClasses = Arrays.asList(
new XmlClass(TestClassSampleOne.class),
new XmlClass(TestClassSampleTwo.class)
);
xmlTest.setXmlClasses(xmlClasses);
XmlGroups xmlGroups = new XmlGroups();
XmlRun xmlRun = new XmlRun();
xmlRun.onInclude("g1");
xmlRun.onInclude("g2");
xmlGroups.setRun(xmlRun);
xmlTest.setGroups(xmlGroups);
TestNG testng = new TestNG();
testng.setXmlSuites(Collections.singletonList(xmlSuite));
TestNarrator listener = new TestNarrator();
testng.addListener((ITestNGListener) listener);
testng.run();
String[] expectedLogs = new String[]{
"{method=[t1],groups=[g1],priority=[1]}",
"{method=[t1],groups=[g1],priority=[1]}",
"{method=[t3],groups=[g2],priority=[2]}",
"{method=[t3],groups=[g2],priority=[2]}",
"{method=[t2],groups=[g2],priority=[3]}",
"{method=[t2],groups=[g2],priority=[3]}",
"{method=[t5],groups=[g2],priority=[4]}",
"{method=[t5],groups=[g2],priority=[4]}",
"{method=[t4],groups=[g2],priority=[5]}",
"{method=[t4],groups=[g2],priority=[5]}"
};
assertThat(listener.getLogs()).containsExactly(expectedLogs);
}
} |
@DarpanSinghal - I spent some more time on this, and to me this looks like TestNG Here's my analysis. When TestNG forms the Directed acyclic graph, it identifies first the below set of methods as eligible for execution. After the above 4 get executed, the next batch that becomes eligible for execution are TestClassSampleOne.t3 (belongs to g2 and has p2 priority) TestClassSampleOne.t2 (belongs to g2 and has p3 priority) TestClassSampleOne.t4 (belongs to g2 and has p5 priority) So here's what the output would be
The reason why I say a bug may have gotten fixed is because The below gif should re-iterate what i am saying (I have intentionally added a delay of 10 seconds between animation so that its easy to follow and find out what is going on) @juherr - WDYT ? |
@krmahadevan I'm not sure to understand your explanation. The priority weight is supposed to define which edge must be followed first: Then, due to
I don't catch the reason why |
The below table should add more context
That is because t5 does not have dependsOn, and t3 has dependsOn. So when we build the graph and ask for freenodes, t3 will not be given, because it has upstream nodes that need to run. I believe that the current functionality is correct. The core concept is that independent methods will run first and only then dependent methods would run. So t3 can never run before t1 and t5 have run to completion, because they are the upstream dependencies for t3 |
But If I remember well, we only removed the priority edges in the past because it generated issues. WDYT? |
Priority is like a soft dependency (An upstream failure will not cause a downstream test to be skipped) But dependsOn is like a hard dependency (An upstream failure will cause downstream tests to be skipped) That's why I was saying that the behaviour is correct. Priority has a say when there are no dependencies. Basically one should not mix hard and soft dependencies (which is what is happening here) |
Thanks for sharing your thoughts but TestNG 6.14.3 is working fine and execution order is as expected. If the principal of hard & soft dependencies is same then why result is different in TestNG 6.14.3 and TestNG 7.4.0 |
@DarpanSinghal - Like I said before, I think a bug that was always there in the system seems to have eventually gotten fixed. |
@krmahadevan I agree with your definition of soft/hard dependencies but it doesn't explain why a soft dependency could not be respected. |
@juherr - Can you please take another look at the table i shared earlier and pls let me know if that answers your question ? I think soft dependency can be honoured only after a hard dependency is honoured. |
I don't get it. In pass 2, why do you think |
Because parallelism is set to classes. Thread count is 2. So the first 4 free nodes would be picked up for execution. And at that point in time group2 methods that have a dependency cannot still be executed since G1 is still not done with execution. |
According to the doc, parallelism is not supposed to have an effect on the order:
Then, for me, the dependencies are:
The first method to run is Once both
The only possible candidate is Once both
The only possible candidate is Once both
The only possible candidate is Once both
The last candidate is I know the current implementation is not that process but I think it is the one we expect. |
@juherr - I still fail to understand as to why do you do think that From what I see in the code, we use priority to sort the free nodes. If you apply this rationale, then |
Sure but it is not expected. See the disabled tests: https://github.com/cbeust/testng/blob/master/testng-core/src/test/java/test/priority/PriorityTest.java |
Hi, |
TestNG Version
Expected behavior
Actual behavior
Is the issue reproducible on runner?
Test case sample
// Another File
//Testng.xml file
The text was updated successfully, but these errors were encountered: