针对任意加载的类运行 JUnit 测试
作为一个更大项目的一部分,我正在尝试实现一些我不确定是否可能的事情,所以我渴望看看是否有人有任何建议!
整个系统:
总的来说,我的系统应该能够提供一个 JUnit 测试类,它与某些提供的接口相匹配。然后将给出不实现此接口的类,但需要检查它们是否能够(即它们是否实现了所有必要的方法)。如果是这样,应该进行一些转换,以便可以针对它运行 JUnit 测试类。
到目前为止我已经实现了:
- 使用 URLClassLoader 加载给定路径和名称的其他类的包
- 使用 JUnitCore 运行 JUnit 测试用例并返回结果的包
问题:
1. 首先,当测试设计为匹配接口时,如何针对实现该接口的类运行 JUnit 测试?我如何(在运行时)指示接口正在测试的实例是加载的类?
- 是否可以扩展它,以便我可以 i) 验证它是否与接口匹配(我假设使用反射来检查相应的方法?)然后 ii) 修改该类,以便可以使用 JUnit 测试对其进行测试班级?
感谢您提供任何可能有助于解决此问题的建议。我很高兴我的描述可能有所欠缺,所以如果您有任何额外的信息可以帮助您给出任何答案,请发表评论!
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 a 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?
- 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!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
您可以使用反射 API 做任何您想做的事情。听起来您应该从教程开始,然后回到这里对于具体问题。给定一个 Class 对象,您可以检查它是否实现给定的接口,创建它的实例,然后像对待任何其他类一样对待它。
编辑:我认为我没有从你的问题中得到这一点,但在这种情况下,你正在寻找 代理是反射 API 的一部分。
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.
既然你有类,你可以使用类提供的 isAssignableFrom 方法,这样
对于第二个问题,你可以检查每个方法并参见 1. 如果存在与接口中定义的方法名称相同的方法, 2. 接口的方法返回类型是否相同以及 3. 方法的参数类型和长度是否相同。当然,第 2 条和第 3 条要正确执行可能会很困难。
那时,我只需创建该接口的一个实例(匿名或私有类),创建该匹配类的 newInstance。并通过接口方法内的反射来调用方法。
现在这就是你如何通过反思来完成它。我并不是像你想象的那样提倡反思:)
Since you have the class you can use the isAssignableFrom method offered by the class such that
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 :)
对于你问题的第一部分;如果您已加载要测试的类的 Class 实例,则可以使用 newInstance() 构造一个实例(如果它有默认构造函数),或者如果需要传递参数,则可以通过 getConstructor 方法构造一个实例。您应该能够从类加载器获取这个类实例。
对于第二部分。您应该能够通过 getMethods() (同样在 Class 实例上)检查公共方法,然后在返回的数组中查找您想要的方法。 Method 类上的一些方法将返回有关参数、异常和返回类型的信息,以验证它们是否是您所需要的。
但是,我非常确定不可能在运行时修改类来添加接口。通过修改字节码也许可以,但我不知道。
另一种方法是编写测试以通过反射调用所有方法,那么对象的类型是什么并不重要,只要它具有正确的方法(您已经检查过)即可。
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).
如果您想让任意类在运行时实现给定的接口(如果其公共 API 与接口匹配),那么 Java 中有多种选择。创建
java.lang.Proxy
来桥接目标类,公开YourInterface
是最简单的方法。您还可以在 AspectJ 中使用 mixin 或使用 CGLIB 子类化目标类并在运行时添加接口。但代理方法的实施起来并不是那么困难。
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, exposingYourInterface
is the easiest way.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.