开发者

Run JUnit test againsts arbitrary loaded class

开发者 https://www.devze.com 2023-02-13 02:12 出处:网络
As part of a larger project, I am attempting to achieve something that I\'m not sure is possible, so am eager to see if anyone has any suggestions!

As part of a larger project, I am attempting to achieve something that I'm not sure is possible, so am eager to see if anyone has any suggestions!

The overall system:

As a whole, my system should be able to be provided with a JUnit test class, that matches some provided interface. Classes will be then given that do not implement this interface, but need to be checked to see if they would be able to (a.k.a. if they implement all necessary methods). If so, some transformation should take place such that the JUnit test class can be run against it.

So far I have implemented:

- A package that loads other classes given 开发者_如何学Goa path and name, using URLClassLoader

- A package that runs a JUnit test case and returns the results, using JUnitCore

The problem:

1. At first, how could I run the JUnit test against a class that does implement the interface when the test is designed to match the interface? How do I (at runtime) dictate that the instance being tested by the interface is the loaded class?

  1. Is it possible to then extend this, such that I could i) verify that it does match the interface (I assume using Reflection to check for corresponding methods?) and then ii) modify that class such that it can be tested using the JUnit test class?

Thanks for any advice that might help towards part of this problem. I appreciate my description may be lacking, so please comment if you have any extra information that would help you give any answer!


You can do everything you want with the reflection API. It sounds like you should start with the tutorial, and then come back here for specific questions. Given a Class object you can check if it implements a given interface, create an instance of it, and then treat it like any other class.

Edit: I don't think I got that from your question, but in that case you are looking for the Proxy part of the reflection API.


how could I run the JUnit test against a class that does implement the interface when the test is designed to match the interface

Since you have the class you can use the isAssignableFrom method offered by the class such that

Class loadedJunitClass = clazz;
MyInterface impl = null;
if(MyInterface.class.isAssignableFrom(loadedJunitClass )){
    impl = (MyInterface) loadedJunitClass.newInstance();
}

For the second question, you can check each method and see 1. If there exists a method with the same method name as defined in the interface, 2. If the method return type is the same from the interface and 3. If the method parameter types and length are the same. Of course 2 and 3 can be tricky to get right.

At that point I would just create an instance of that interface (anonymous or a private class), create a newInstance of that matching class. And invoke the methods through reflection within the interface's methods.

Now that is how you can get it done with reflection. I am not advicating reflection as you can imagine :)


For the first part of your question; if you have the loaded Class instance for the class you want to test you can construct one with newInstance() if it has a default constructor, or via the getConstructor methods if you need to pass parameters. You should be able to get this Class instance from the class loader.

For the second part. You should be able to check the public methods via getMethods() (again on the Class instance) then look through the returned array for the methods you want. There are methods on the Method class that will return information about parameters, exceptions and return type to verify they are what you require.

However, I am pretty certain it is not possible to modify the class at runtime to add the interface. It might be possible by modifying the byte code, but I don't know about that.

An alternative would be to write your test to call all method via reflection, then it doesn't matter what the type of the object is just that it has the right methods (which you've already checked).


If you want to make arbitrary class to implement given interface at runtime if its public API matches the interface, you have several options in Java. Creating java.lang.Proxy to bridge the target class, exposing YourInterface is the easiest way.

YourInterface i = (YourInterface) Proxy.newProxyInstance(
        this.getClass().getClassLoader(), 
        new Class[]{YourInterface.class},
        new InvocationHandler() {

    @Override
    public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
        //run method on your target class here using reflection
    }

 });

You can also use mixins in AspectJ or subclass your target class using CGLIB and add interface at runtime. But the proxy approach is not that hard-core to implement.

0

精彩评论

暂无评论...
验证码 换一张
取 消