testng-team / testng

TestNG testing framework
https://testng.org
Apache License 2.0
1.99k stars 1.02k forks source link

Wrong automatic createClassDependencies behavior with testng.xml based packages.package definition #463

Open bzim opened 11 years ago

bzim commented 11 years ago

When using a testng.xml definition file, which contains a test definition with package based scanning of test classes. Like:

<suite name="acounting-export" preserve-order="true" configfailurepolicy="skip">
    <test name="Base">
        <packages>
            <package name="accounting.export" />
            <package name="accounting.export.test" />
        </packages>
    </test>
</suite>

The graph based dependency evaluation ist wrong, when one of the found classes does not contain any test methods. This can be the case if the package name is not only for testng tests, but can contain services etc. In this scenario the following method from the TestRunner:

private ListMultiMap<ITestNGMethod, ITestNGMethod> createClassDependencies(
      ITestNGMethod[] methods, XmlTest test)
  {
    Map<String, List<ITestNGMethod>> classes = Maps.newHashMap();
    // Note: use a List here to preserve the ordering but make sure
    // we don't add the same class twice
    List<XmlClass> sortedClasses = Lists.newArrayList();

    for (XmlClass c : test.getXmlClasses()) {
      classes.put(c.getName(), new ArrayList<ITestNGMethod>());
      if (! sortedClasses.contains(c)) sortedClasses.add(c);
    }

    // Sort the classes based on their order of appearance in the XML
    Collections.sort(sortedClasses, new Comparator<XmlClass>() {
      @Override
      public int compare(XmlClass arg0, XmlClass arg1) {
        return arg0.getIndex() - arg1.getIndex();
      }
    });

    Map<String, Integer> indexedClasses1 = Maps.newHashMap();
    Map<Integer, String> indexedClasses2 = Maps.newHashMap();
    int i = 0;
    for (XmlClass c : sortedClasses) {
      indexedClasses1.put(c.getName(), i);
      indexedClasses2.put(i, c.getName());
      i++;
    }

    ListMultiMap<String, ITestNGMethod> methodsFromClass = Maps.newListMultiMap();
    for (ITestNGMethod m : methods) {
      methodsFromClass.put(m.getTestClass().getName(), m);
    }

    ListMultiMap<ITestNGMethod, ITestNGMethod> result = Maps.newListMultiMap();
    for (ITestNGMethod m : methods) {
      String name = m.getTestClass().getName();
      Integer index = indexedClasses1.get(name);
      // The index could be null if the classes listed in the XML are different
      // from the methods being run (e.g. the .xml only contains a factory that
      // instantiates methods from a different class). In this case, we cannot
      // perform any ordering.
      if (index != null && index > 0) {
        // Make this method depend on all the methods of the class in the previous
        // index
        String classDependedUpon = indexedClasses2.get(index - 1);
        List<ITestNGMethod> methodsDependedUpon = methodsFromClass.get(classDependedUpon);
        if (methodsDependedUpon != null) {
          for (ITestNGMethod mdu : methodsDependedUpon) {
            result.put(mdu, m);
          }
        }
      }
    }

    return result;
  }

creates no method dependencies when the successor class is not a test class with test methods. This results in a broken dependency tree for all following test methods. The intended behavior is that any method of a test class depends on all methods of the successor class!

Possible solutions are:

If desired, i can provide a pull request.

bzim commented 11 years ago

maybe related to #224