1

I am running test cases (TestNg testcases) programmatically, using java, by creating testng xml through code. Running Perfectly okay.

Problem:

I want to execute testcases which are being uploaded live, meaning my server is running and I am uploading new recorded test cases( they are not compiled, passing .java file) into this running server which are passed to above created testng xml java code. But I am getting error i.e Cannot find class in classpath: com.packagename.SampleTestNgTestcase While I rerun my server and call this functionality, it execute the test case.

I have been browsing and trying to find solution by practicing the techniques to compile a TestNg testcase, yet no success, as no where getting how to compile a test case.

Any help regarding what is the way I can execute the non-compiled test cases or other way, how to compile the testcase.java file programmatically, is greatly appreciated. If needed more detailed information about the question clearance, I will!

Das Khatri
  • 93
  • 6

1 Answers1

0

Compiling a TestNG test class is in no way different from you compiling a regular java class.

Assuming that you don't have any issues with your CLASSPATH (the below code does not account for that), here's a simple example that you can use to get started.

Reference: Most of the implementation is heavily inspired and drawn from this blog.

Lets assume that you have a text file called sample.txt whose contents are as below:

package foo.bar;
import org.testng.annotations.Test;

public class Example {
    @Test
    public void testMethod() {
        System.err.println("Hello world");
    }
}
import java.nio.file.Path;

public class ClassInfo {
  String packageName;
  String className;
  String sourceCode;
  Path javaFile;
  Path classFile;
}
import static java.nio.charset.StandardCharsets.UTF_8;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.stream.Collectors;
import javax.tools.JavaCompiler;
import javax.tools.ToolProvider;
import org.testng.TestNG;

public class DynamicTestNgExecutor {

  public static void main(String[] args) throws Exception {
    DynamicTestNgExecutor.runTests("src/test/resources/sample.txt", "foo.bar.Example");
  }

  public static void runTests(String sourcePath, String className) throws Exception {
    ClassInfo classInfo = parse(sourcePath, className);
    saveSource(classInfo);
    compileSource(classInfo);
    runClass(classInfo, className);
  }

  private static void runClass(ClassInfo classInfo, String className)
      throws MalformedURLException, ClassNotFoundException {
    URL classUrl = classInfo.javaFile.getParent().toFile().toURI().toURL();
    if (!classInfo.packageName.isEmpty()) {
      File file = classInfo.javaFile.toFile();
      int count = classInfo.packageName.split("\\Q.\\E").length;
      for (int i = 0; i <= count; i++) {
        file = file.getParentFile();
      }
      classUrl = file.toURI().toURL();
    }
    URLClassLoader classLoader = URLClassLoader.newInstance(new URL[] {classUrl});
    Class<?> clazz = Class.forName(className, true, classLoader);
    TestNG testNG = new TestNG();
    testNG.setTestClasses(new Class[] {clazz});
    testNG.setVerbose(2);
    testNG.run();
  }

  public static ClassInfo parse(String sourcePath, String className) throws FileNotFoundException {
    InputStream stream = new FileInputStream(sourcePath);
    String separator = System.getProperty("line.separator");
    BufferedReader reader = new BufferedReader(new InputStreamReader(stream));
    ClassInfo info = new ClassInfo();
    info.className = className;
    info.sourceCode = reader.lines().collect(Collectors.joining(separator));
    info.packageName = packageName(info.sourceCode);
    return info;
  }

  private static void compileSource(ClassInfo classInfo) {
    JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
    compiler.run(System.in, System.out, System.err, classInfo.javaFile.toFile().getAbsolutePath());
    classInfo.classFile = classInfo.javaFile.getParent().resolve(classInfo.className + ".class");
  }

  public static void saveSource(ClassInfo classInfo) throws IOException {
    String folder = folderName(classInfo.packageName);
    String tmpProperty = System.getProperty("java.io.tmpdir") + File.separator + folder;
    final boolean success = new File(tmpProperty).mkdirs();
    if (!success) {
      throw new IllegalStateException("Encountered problems when creating the package structure " + tmpProperty);
    }
    classInfo.javaFile = Paths.get(tmpProperty, simpleClassName(classInfo.className) + ".java");
    Files.write(classInfo.javaFile, classInfo.sourceCode.getBytes(UTF_8));
  }

  private static String simpleClassName(String className) {
    String[] parts = className.split("\\Q.\\E");
    if (parts.length == 1) {
      //No package name in the class
      return parts[0];
    }
    int lastButOne = parts.length - 1;
    return parts[lastButOne];
  }

  private static String folderName(String pkg) {
    if (pkg.isEmpty()) {
      return "";
    }
    pkg = pkg.replaceAll("\\Q.\\E", "/");
    return pkg;
  }

  private static String packageName(String source) {
    String separator = System.getProperty("line.separator");
    String pkg =
        Arrays.stream(source.split(separator))
            .filter(each -> each.contains("package"))
            .findAny()
            .orElse("");
    if (pkg.isEmpty()) {
      return "";
    }
    return pkg.replaceAll("package ", "").replaceAll(";", "");
  }
}
Krishnan Mahadevan
  • 14,121
  • 6
  • 34
  • 66