4

I'm using the following code to recognize test classes in a project, the whole idea is to find test classes and to compare the amount of test code with the production code! Here is a piece of my code which is responsible to find test class and count the lines:

     for (File f : list) {
        if (f.isDirectory()) {
            walk(f.getAbsolutePath());
        }

        if (f.getName().endsWith(".java")) {

            System.out.println("File:" + f.getName());
            countFiles++;

            Scanner testScanner = new Scanner(f);
            while (testScanner.hasNextLine()) {

                String test = testScanner.nextLine();
                if (test.contains("org.junit") || test.contains("org.mockito") || test.contains("org.easymock")) {
                    hasTestLines = true;
                    //      break;
                }
                testCounter++;
            }

But after running the code on several projects, I realized that the idea of finding test classes that contain Unit or EasyMock or Mockito is not the best practice to find test classes, as several projects use their own test methods! So the question is there a better way than mine to define test classes?

Thanks

Kedar Mhaswade
  • 4,535
  • 2
  • 25
  • 34
user5923402
  • 217
  • 3
  • 12
  • If you are going to be looking for custom test classes, where I could name classes and functions anything I want, then you may be out of luck. That being said generally people would name their functions "test..." So you could count the number of functions that have "test" in their name. Another issue I see is that your code would recognize files that have `org.junit` in comments. – McAngus Mar 09 '16 at 17:13
  • So you think, that custom test classes should be studied and counted manually? – user5923402 Mar 09 '16 at 17:15
  • 1
    Is this a Maven project? Can you utilize Maven plugins like e.g. [`Sonar` plugin](http://docs.sonarqube.org/display/SONAR/Analyzing+with+SonarQube+Scanner+for+Maven) for code coverage? – Kedar Mhaswade Mar 09 '16 at 17:17
  • Unless you know the pattern that is used for these test classes. For example I could name a class `TClasses` with functions `tInt` and `tFloat`. For this class the "t" in front of names would signify tests. But there's no easy way for you to know that ahead of time. Unless that is the standard for all (or some) projects that you are analyzing. – McAngus Mar 09 '16 at 17:21

4 Answers4

1

could'nt you just load classes and pass them as parameter to a test runner like

org.junit.runner.JUnitCore.runClasses(TestClass1.class, ...);

and work with the output of the test runner.

Now the test runner searches for test methods in a class.

If the class doesn't contain any, it will not succeed and therefore be a production class. (assumed that all test classes succeed !)

In my implementation I just count the number of classes, but you can extend it to count the number of lines and then compare them.

here the implementation:

 public void compareTestAndProduction () {

    // pattern to split the name of class from it's extension
    String pattern = "(.*)(?=.class)";

    // package to proove
    String packageName = "stackoverflow.test";

    // relative path of package
    String packagePath = "stackoverflow/test";

    // counter for number of test classes
    int testCounter = 0;

   // counter for number of production classes
    int codeCounter = 0;

    // classloader for test and production classes
    ClassLoader classLoader = Thread.currentThread().getContextClassLoader();

    try {
        // load package resources to file
        Enumeration enumeration = classLoader.getResources(packagePath);
        URL url = (URL) enumeration.nextElement();
        File classFiles = new File(url.getFile());

        // read all subfiles in File
        // which contains the package dir and all classes
        for (File classFile : classFiles.listFiles()) {
            String classNameWithExtension = classFile.getName();
            // proov if name of class is no directory
            if (classNameWithExtension.endsWith(".class")) {
                // extend the class with the package name
                // and get rid of the extension .class
                String className = packageName + "." + classNameWithExtension.split("[.]")[0];
                
                // load class
                Class c = classLoader.loadClass(className);
                
                // run the class with a test runnner
                // which will search class for test methods
                Result result = org.junit.runner.JUnitCore.runClasses(c.newInstance().getClass());

                // if testmethods found
                // and they are successful
                // raise testcounter
                if(result.wasSuccessful())
                    testCounter++;
                else codeCounter++;


            }
        }
        System.out.println("Test classes:\n" + testCounter);
        System.out.println("Production classes:\n" + codeCounter);
    } catch (IOException e) {
        e.printStackTrace();
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    } catch (InstantiationException e) {
        e.printStackTrace();
    } catch (IllegalAccessException e) {
        e.printStackTrace();
    }
}

In my case

Test classes:

1

Production classes:

2

Community
  • 1
  • 1
jam
  • 1,253
  • 1
  • 12
  • 26
  • I cant really get what your idea, could you please describe a bit more? thanks – user5923402 Mar 09 '16 at 23:00
  • the idea is to find the test methods/classes by a test runner and not by occurence of some keywords like test, mockito ...., since the testrunner knows how to do it. – jam Mar 10 '16 at 07:15
0

In java normally production codes are kept in src/main/java and test code in src/test/java

Hemant Patel
  • 3,160
  • 1
  • 20
  • 29
  • Thanks for your answer! In facte, I was thiniking about changing my logic to your logic, but I was unsure if that works in all cases? – user5923402 Mar 09 '16 at 17:24
  • Almost in all cases it is followed, I have not seen any project with any other directory structure. Project build tools like gradle/maven define the same directory structure as default – Hemant Patel Mar 09 '16 at 17:29
  • 1
    This is the logic for Maven https://maven.apache.org/guides/introduction/introduction-to-the-standard-directory-layout.html – Gonçalo Cardoso Mar 09 '16 at 17:42
0

Not sure what you want to achieve but test and actual code should be kept separate. You can use plugins like emma, cobertura, sonar for code coverage.

However if you are doing some exercise then see following options.

The test classes could have a Test prefix or suffix.

OR

The test classes implements/extends an interface e.g. TestCase.

OR

The test classes uses annotation at the top e.g. @TestCase.

OR

The test class having methods which are annotated e.g. @Test.

Bhushan Bhangale
  • 10,921
  • 5
  • 43
  • 71
  • I'm actually doing a research,I'm supposed to analyze a sufficient amount of projects and see how much test code have those project had in comparsion to producing code, after collecting data I'll try to come up with recommendation to be referred to by testers and developers. My research will try to answer a question like, how much test code should be written to a project containing 10K lines of code written by 5 developers? But regarding your answer what if a producing class contains @Test in a comment then the class will be counted as test class! – user5923402 Mar 09 '16 at 17:39
  • For your research use the tools I suggested and it will tell how much code coverage a project has. Sonar will tell you number of lines and percentage. You do not need to write your code to find that out as your research is not how to develop code coverage tool. – Bhushan Bhangale Mar 09 '16 at 17:57
  • Will it tell you how many test lines you have? As you may already know, having 100% percent coverage doesnt gurantee a bug free program, so I'm not really interested in the coverage part, I will be considering it for sure, but it won't be my first thing to look at! Do you think I have a point in that? feel free to discuss and write your thoughts, as I really like hearing others thoughts and ideas! thanks – user5923402 Mar 09 '16 at 18:12
  • That is correct and there is no way to find out. If a project has decent level of coverage then chances of its quality to be good is high. – Bhushan Bhangale Mar 09 '16 at 18:15
0

As long as you and your collaborators are consistent in how you make custom test classes, i.e. if you all name a test class as SomeClassTest or TestSomeClass, or perhaps you even use static methods for testing. But as long as you're consistent you should only have to look for in this example the word "test" in the title. Or if you use static method, probably a bit trickier.

Chexxor
  • 406
  • 6
  • 17