【问题标题】:Run JUnit test againsts arbitrary loaded class针对任意负载类运行 JUnit 测试
【发布时间】:2011-02-25 06:21:03
【问题描述】:

作为一个更大项目的一部分,我正在尝试实现一些我不确定是否可行的事情,所以很想看看是否有人有任何建议!

整个系统:
作为一个整体,我的系统应该能够提供一个 JUnit 测试类,它与一些提供的接口相匹配。然后将给出不实现此接口的类,但需要检查它们是否能够(也就是它们是否实现了所有必要的方法)。如果是这样,应该进行一些转换,以便可以针对它运行 JUnit 测试类。

到目前为止我已经实现了:
- 使用 URLClassLoader
加载给定路径和名称的其他类的包 - 使用 JUnitCore 运行 JUnit 测试用例并返回结果的包

问题:
1. 首先,当测试旨在匹配接口时,如何针对实现接口的类运行 JUnit 测试?我如何(在运行时)指示接口测试的实例是加载的类?

  1. 是否可以扩展它,以便我可以 i) 验证它是否与接口匹配(我假设使用反射来检查相应的方法?)然后 ii) 修改该类以便可以使用它进行测试JUnit 测试类?

感谢任何可能有助于解决部分问题的建议。我很感激我的描述可能会有所缺失,所以如果您有任何额外的信息可以帮助您给出任何答案,请发表评论!

【问题讨论】:

  • 您要在这里解决的根本问题是什么?

标签: java reflection junit


【解决方案1】:

您可以使用反射 API 做任何您想做的事情。听起来您应该从the tutorial 开始,然后回到这里询问具体问题。给定一个 Class 对象,您可以检查它是否实现给定接口,创建它的实例,然后像对待任何其他类一样对待它。

编辑:我不认为我从您的问题中得到了这一点,但在这种情况下,您正在寻找反射 API 的 Proxy 部分。

【讨论】:

  • 谢谢,我知道这部分事情的正确方向。但是,我将如何处理我所描述的扩展版本,我需要 i)查看该类是否具有实现接口的所有方法,ii)如果是,则将其视为测试。另外,当测试只匹配接口时,如何在 JUnit 中测试匹配接口的类?
【解决方案2】:

我如何运行 JUnit 测试 一个确实实现了 当测试被设计为接口 匹配界面

既然你有类,你可以使用类提供的 isAssignableFrom 方法,这样

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

对于第二个问题,你可以检查每个方法,看看1.是否存在与接口中定义的方法名称相同的方法,2.方法返回类型是否与接口相同,3.如果方法参数类型和长度相同。当然,要正确使用 2 和 3 可能会很棘手。

那时我只需创建该接口的实例(匿名或私有类),然后创建该匹配类的 newInstance。并通过接口方法内的反射调用方法。

现在你可以通过反射来完成它。我并不是在提倡你可以想象的反思:)

【讨论】:

    【解决方案3】:

    对于您问题的第一部分;如果您已经为要测试的类加载了 Class 实例,如果它具有默认构造函数,则可以使用 newInstance() 构造一个,如果需要传递参数,则可以通过 getConstructor 方法构造一个。您应该能够从类加载器中获取这个 Class 实例。

    第二部分。您应该能够通过 getMethods()(再次在 Class 实例上)检查公共方法,然后在返回的数组中查看您想要的方法。 Method 类中有一些方法将返回有关参数、异常和返回类型的信息,以验证它们是您需要的。

    但是,我很确定在运行时修改类以添加接口是不可能的。通过修改字节码可能可以,但我不知道。

    另一种方法是编写测试以通过反射调用所有方法,然后对象的类型无关紧要,只要它具有正确的方法(您已经检查过)。

    【讨论】:

      【解决方案4】:

      如果你想让任意类在运行时实现给定接口,如果它的公共 API 匹配接口,你在 Java 中有几个选项。创建java.lang.Proxy 来桥接目标类,暴露YourInterface 是最简单的方法。

      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
          }
      
       });
      

      您还可以在 AspectJ 中使用 mixins 或使用 CGLIB 子类化您的目标类并在运行时添加接口。但是代理方法并不是很难实现。

      【讨论】:

        猜你喜欢
        • 2012-01-04
        • 1970-01-01
        • 1970-01-01
        • 2011-01-30
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-03-23
        • 2013-01-06
        相关资源
        最近更新 更多