使用谷歌的反思库单元测试失败,只有当Maven的执行(Unit test using the Ref

2019-07-04 04:18发布

我使用的是谷歌的反思库在类路径查询某些资源。 这些资源都位于相同的位置比我的项目中的类。

我写了一些单元测试时作为Eclipse的一个单元测试执行的成功,但是当我尝试使用Maven来执行它们(用maven install为例),预期它们不工作。 一些调试后,显然的问题是,当使用Maven执行的思考图书馆找不到类路径URL的资源所在的位置。

我来到这个结论研究思考如何确定应检查类路径的URL。 作为一个例子,下面的方法显示了思考如何找到给定的类加载器可用的类路径的URL(原始的思考方法已被简化一个位):

public static Set<URL> forClassLoader(ClassLoader... classLoaders) {
    final Set<URL> result = Sets.newHashSet();
    for (ClassLoader classLoader : classLoaders) {
        while (classLoader != null) {
            if (classLoader instanceof URLClassLoader) {
                URL[] urls = ((URLClassLoader) classLoader).getURLs();
                if (urls != null) {
                    result.addAll(Sets.<URL>newHashSet(urls));
                }
            } 
            classLoader = classLoader.getParent();
        }
    }
    return result;
}

总之,它是穿越类装载器层次要求为每个类加载器的URL。

当在Eclipse我从这样的一个单元测试调用以前的方法:

    ClassLoader myClassClassLoader = <MyClass>.class.getClassLoader(); //<MyClass> is in the same classpath url than the resources I need to find
    Set<URL> urls = forClassLoader(myClassClassLoader);
    for(URL url : urls) {
      System.out.println("a url: " + url);

正如所料,我可以看到,被配置为我的项目的一部分的类路径的URL(其中包括许多其他的网址):

file:<MY_PROJECT_PATH>/target/classes/
file:<MY_PROJECT_PATH>/target/test-classes/

与思考工程作为魅力(资源思考应该找到位于file:<MY_PROJECT_PATH>/target/classes/ )。

然而,当测试由Maven的执行,我意识到,这些URL条目从被返回的集中缺少forClassLoader方法,和的思考方法,其余如预期这个问题不工作。

该“令人吃惊”的是,如果我写这篇文章时,单元测试是由行家执行:

ClassLoader myClassClassLoader = <MyClass>.class.getClassLoader();
url = myClassClassLoader.getResource("anExistingResource");
System.out.println("URL: "+url); //a valid URL

我可以看到的类加载器仍然可以解决我试图找到资源。 我很疑惑为什么当使用Maven执行forClassLoader方法不会在我的项目的返回将classpath设置的URL包括,但同时它能够解决位于此类URL资源(!)。

什么是这种行为的原因是什么? 有任何解决方法,我可以试着让思考图书馆工作时,作为Maven的运行单元测试的一部分调用?

Answer 1:

你可能会使用m2eclipse的,这增加了的东西在自己类路径。 命令行Maven的工作方式不同。 您可能会发现一些选项,这将有助于 。



Answer 2:

解决它。 发布万一有人在寻找解决方案在未来同样的问题。

当执行一个项目的单元测试,Maven不包括(明确)在类路径中包含所有的依赖关系。 相反,它宣布在位于“目标/神火/ surefirebooter_NUMBER_THAT_LOOKS_LIKE_TIME_STAMP.jar”一个TMP罐子的依赖。 这个jar文件仅包含声明该项目的类路径的清单文件。

该方法forClassLoader在思考库不返回一组URL以有效类路径(即,在清单文件的类路径条目被忽略)。 为了克服这个问题,我只是实现了这个简单的方法:

public static Set<URL> effectiveClassPathUrls(ClassLoader... classLoaders) {
    return ClasspathHelper.forManifest(ClasspathHelper.forClassLoader(classLoaders));
}

该方法forManifest (也反思库的一部分),增加了一组被作为参数,在包含在集合中的任何jar文件清单文件中声明丢失的类路径条目的类路径的URL。 通过这种方式,方法返回一组与项目的有效类路径的URL。



Answer 3:

我有同样的问题。 添加以下网址的伎俩我。

ConfigurationBuilder cb = new ConfigurationBuilder();
cb.setUrls(...);
cb.addUrls(YourClassName.class.getProtectionDomain().getCodeSource().getLocation());


Answer 4:

我只是思考库(版本0.9.11)遇到同样的问题,只是执行单元测试时从Maven的构建。 在接受的答案所提供的链接指向我在正确的方向。

一个简单的POM文件改变我一定能成功的插件解决了这个问题:

            <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-surefire-plugin</artifactId>
            <version>2.21.0</version>
            <configuration>
                <useSystemClassLoader>false</useSystemClassLoader>
            </configuration>
        </plugin>
        <plugin>
            <artifactId>maven-failsafe-plugin</artifactId>
            <version>2.21.0</version>
            <configuration>
                <useSystemClassLoader>false</useSystemClassLoader>
            </configuration>
            <executions>
                <execution>
                    <goals>
                        <goal>integration-test</goal>
                        <goal>verify</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>

所述<useSystemClassLoader>配置参数的缺省值为“真”。 它强制为“假”似乎解决我的单元测试的类加载器的问题。



Answer 5:

还有,你可以创建,使万无一失失败的几个问题。

  1. 有一个命名约定; 测试套件应该叫“TestBlaBla”或“BlaBlaTest”; 开始的时候还是用字“测试”结束。

  2. 如前面提到的,在Maven的类路径是更受限制的比在Eclipse作为蚀(愚蠢)不编译的类路径从测试类路径分开。

  3. 神火自由地从任何顺序不同的测试套件运行测试用例。 当运行多个测试套件初始化一些常见的碱(诸如内存数据库或JNDI上下文),其可产生冲突,其中测试套件开始相互影响。 你需要注意正确的隔离测试套件。 我使用的技巧是使用单独的内存数据库为套房,我在每测试套件代替每单位测试初始化​​共享的东西。

3是最难调试我可以告诉你; 每当一些工程在Eclipse中,而不是在Maven的我自然认为我做错了在隔离测试套件。



文章来源: Unit test using the Reflections google library fails only when executed by Maven