0

I'm currently testing api's that are given to us in a jar. I am attempting to get a 'coverage' or list of the jar-methods and objects that we have touched or that at least our source code references.

What we have or will have available is a text format of "here is a list of API's"

And we need to cross reference our own application to ensure we are covering the API's listed.

...

Here's a simplified example... Below I listed an example of the external code available from the jar, and the code we have using those APIs.

-- EXTERNAL_USE_CLASS -- MOCKS the external JAR with public API's that we need to cover

package external_api;

public class EXTERNAL_USE_CLASS {
    String myString;
    Integer myInteger;
    Boolean has_ran;
    public EXTERNAL_USE_CLASS() {
        myString = "initial_string";
        myInteger = 4;
        has_ran = false;
    }
    public String getMyString() {
        return myString;
    }
    public void setMyString(String myString) {
        this.myString = myString;
    }
    public Integer getMyInteger() {
        return myInteger;
    }
    public void setMyInteger(Integer myInteger) {
        this.myInteger = myInteger;
    }
    public Boolean getHas_ran() {
        return has_ran;
    }
    public void setHas_ran(Boolean has_ran) {
        this.has_ran = has_ran;
    }
}

My project will import the above as a jar and add it to the build path. What my code will do, is something like this:

UseExtJar -- mocks our test application using the external jars objects/mathods

import external_api.EXTERNAL_USE_CLASS;

public class UseExtJar {
    static EXTERNAL_USE_CLASS u = new EXTERNAL_USE_CLASS();

    //below is callable via a CLI interface test APP.
    public static void test_basics() {
        Boolean hasRan = u.getHas_ran();
        Integer getInt = u.getMyInteger();
        String getString = u.getMyString();
        System.out.println("u.getHas_ran()"+hasRan);
        System.out.println("u.getMyInteger()"+getInt);
        System.out.println("u.getMyString()"+getString);
    }
}

And what I am interested in exposing are all the API's touched from the external Jar.

(which namely would these lines)

    Boolean hasRan = u.getHas_ran();
    Integer getInt = u.getMyInteger();
    String getString = u.getMyString();

And If possible... I'd like to be able to print out some report to the effect of saying

Your Object Method 'test_basics' has used the following api's:
--external_api.EXTERNAL_USE_CLASS.getHas_ran()
--external_api.EXTERNAL_USE_CLASS.getMyInteger() --external_api.EXTERNAL_USE_CLASS.getMyString()

The above names I had to get by going to my test-class and right clicking in eclipse and saying 'copy qualified name'.

Which is kind of a pain if we have to do this for 1,000's of APIs.... I just figured theres some way to logically print out a trace.

It could be I just dont know the proper google search terms, and this is a common easy task.

Much Appreciated for any help/pointers.

3 Answers3

1

You can solve part of this problem using reflection if you know the class's name to get information about it. You can print and even exercise the methods in the class

import java.lang.reflect.*;

public class DumpMethods { 

  public static void main(String args[])
  {
     try {
        Class c = Class.forName("MyClassName");
        Method m[] = c.getDeclaredMethods();
        for (int i = 0; i < m.length; i++)
        System.out.println(m[i].toString());
     }
     catch (Throwable e) {
        System.err.println(e);
     }
  }
}

Here is a beginner's tutorial.

It wouldn't be a terrible stretch for you to effect some library code to alleviate some of your burden.

Unfortunately analyzing the contents of a jar is not so simple. Once the classes of jar are loaded into the concept of a jar kind of disappears. The default classloaders only use the package name as a key for identifying a unique class and deciding whether it exists in the classloader. So you can't really even loop through the classes in a package let alone the contents of a jar.

To do this you could create a custom classloader that analyzed the jar and recorded information as it gets slurped up off the classpath.

halfer
  • 19,824
  • 17
  • 99
  • 186
nsfyn55
  • 14,875
  • 8
  • 50
  • 77
0

When you have to write a mock Class for every API class used

System.out.println(MyMockedClass.class.getCanonicalName());

gets you the qualified name of the class you're mocking.

Something like this

Object doMethod(String name){
    try {
        Method method = u.getClass().getDeclaredMethod(name);
        System.out.println("called: " + name);
        try {
            return (String)method.invoke(this);
        } catch (IllegalArgumentException e) {
            return false;
        } catch (IllegalAccessException e) {
            return false;
        } catch (InvocationTargetException e) {
            return false;
        }
    } catch (NoSuchMethodException e) {
        return false;
    }
}

could give you a way of calling and printing each method you call.

For methods called with arguments it would get more difficult.

Pao
  • 843
  • 5
  • 17
0

Thanks.

I started with reflection as you suggested, and then drifted towards ASM because I'm working with bytecode.


I pulled my reference from 2 links referencing ASM and reflection

Java: Easy way to get method stub out of class files within a JAR file? Reflection?

How can I find all the methods that call a given method in Java?


My solution essentially solves the problem in 2 steps

1. read all the target-methods from the external-jar

via ASM, read in all class/method objects that are public that satisfy a class path (com.my.class.object.*) and some opt-code filters (not private, not abstract, etc) and append all that satisfy the filtering to a list of objects storing the class/method.

2. foreach target-method, check if its existent in our source code.

For each target class/method found, just as the link provided above does, I can check where, and print all the occurances with line/filenames etc.

Community
  • 1
  • 1