如何使Eclipse和Tycho的JUnit4 + Hamcrest 1.3 + Mockito工作

时间:2017-07-20 15:14:24

标签: eclipse junit mockito tycho hamcrest

我已成功 JUnit 4.12 + Hamcrest 1.3 + Mockito 2.8.47 Eclipse中工作因此,当我将它们作为依赖项添加时,我的测试将会运行。

(我这样做的方法是使用p2-maven-plugin捆绑以下内容 从Maven Central到插件/功能的工件,并通过P2提供它们:

  • junit 4.12
  • org.mockito.mockito-core 2.8.47
  • org.hamcrest.all 1.3.0

将插件作为依赖项添加到我的测试片段中进行测试 在Eclipse中运行。

但是,相同片段的 Tycho 版本将失败 以下消息:

java.lang.LinkageError: loader constraint violation: loader (instance of org/eclipse/osgi/internal/loader/EquinoxClassLoader) previously initiated loading for a different type with name "org/hamcrest/Matcher" 
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClass(ClassLoader.java:763)
at org.eclipse.osgi.internal.loader.ModuleClassLoader.defineClass(ModuleClassLoader.java:273)
at org.eclipse.osgi.internal.loader.classpath.ClasspathManager.defineClass(ClasspathManager.java:632)
at org.eclipse.osgi.internal.loader.classpath.ClasspathManager.findClassImpl(ClasspathManager.java:586)
at org.eclipse.osgi.internal.loader.classpath.ClasspathManager.findLocalClassImpl(ClasspathManager.java:538)
at org.eclipse.osgi.internal.loader.classpath.ClasspathManager.findLocalClass(ClasspathManager.java:525)
at org.eclipse.osgi.internal.loader.ModuleClassLoader.findLocalClass(ModuleClassLoader.java:325)
at org.eclipse.osgi.internal.loader.BundleLoader.findLocalClass(BundleLoader.java:345)
at org.eclipse.osgi.internal.loader.BundleLoader.findClassInternal(BundleLoader.java:423)
at org.eclipse.osgi.internal.loader.BundleLoader.findClass(BundleLoader.java:372)
at org.eclipse.osgi.internal.loader.BundleLoader.findClass(BundleLoader.java:364)
at org.eclipse.osgi.internal.loader.ModuleClassLoader.loadClass(ModuleClassLoader.java:161)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
at org.hamcrest.MatcherAssert.assertThat(MatcherAssert.java:12)
at org.junit.Assert.assertThat(Assert.java:956)
at org.junit.Assert.assertThat(Assert.java:923)

所以似乎其他一些插件正在加载包 我的片段之前的org.hamcrest.Matcher 。这可能是应该的 到周围的进口/出口/部分进口/部分出口混乱 JUnit / Hamcrest / Mockito设置。

有没有人有一个想法 - 甚至更好:一个工作的例子 - 如何 让三个组件在IDE中一起工作(快速 检查测试是否运行)和Tycho(用于构建期间的检查)?

2 个答案:

答案 0 :(得分:1)

似乎加载器想要捆绑中的依赖项。

但我猜你还没有将你的测试库放在一个包中。

您可以尝试将它们添加到产品的依赖项中,以了解它的反应。

答案 1 :(得分:0)

背景

问题的根源在于,org.junit 已经依赖于 org.hamcrest.core。因此,当您的测试插件依赖于 org.hamcrest.all(包含 hamcrest-core 和所有其他 hamcrest 工件的所有内容)时,在 hamcrest-core 中指定的所有类都存在两次。一次在 hamcrest-core 包中,一次在 hamcrest-all 包中,这就是您收到链接错误的原因。

如果您在 Eclipse 的 Manifest-Editor 中打开 org.junit 的 Manifest 并转到“Dependencies”选项卡,它应该会在“Required Plug-ins”部分显示 org.hamcreast.core 和 {{ 1}} 应该重新导出。或者在原始清单中它应该是这样的:

org.hamcreast.core

解决方案 1 - 添加 hamcrest 子模块

我没有将包含 Require-Bundle: org.hamcrest.core;bundle-version="1.3.0";visibility:=reexport 的所有 hamcrest 模块作为依赖项添加到我的 Eclipse 测试包/项目(通过“Require-Bundle”),而是添加了我需要的 hamcrest 子模块,除了 hamcrest -core(因为在我的情况下它已经重新导出了)。对我来说,hamcrest-library 就足够了。

可用的 hamcrest 子模块是(根据 org.hamcrest:hamcrest-parent pom,可以在这里找到:https://repo1.maven.org/maven2/org/hamcrest/hamcrest-parent/1.3/hamcrest-parent-1.3.pom):

  • hamcrest 核心
  • hamcrest 图书馆
  • hamcrest 生成器
  • hamcrest 整合

创建包含所需包的 p2-Repo

当使用 Maven 和 'org.reficio:p2-maven-plugin' 构建包含上述测试包的 p2-repo 时,maven-artifacts 到 OSGi-bundles 的转换不会产生完全工作的结果默认情况下。 将 maven 模块转换为完整的 OSGi 包主要包括配置 MANIFEST.MF 以包含正确的条目。为此,p2-maven-plugin 使用“bnd 工具”。 默认情况下,当该模块转换为 OSGi 包时,maven 模块的所有 maven 依赖项提供的 Java 包作为可选 hamcrest.all 添加。

就我而言,这导致 Imported-package 包仅通过其 MANIFEST.MF 中的 org.hamcrest.library 引用来自 hamcrest-core 的包。 但不幸的是,只指定了这个,Equinox-ClassLoader 在测试运行时没有从 hamcrest-core 中找到类并抛出相应的异常。也许这也是因为hamcrest-core和hamcrest-library有一个包“org.hamcrest”,bnd-tools又把一个bundle的导出包添加到了导入包中。

我的解决方案是分别指示 Import-Package 和 bnd-tools 将 org.reficio:p2-maven-plugin 作为“Require-Bundle”添加到 hamcrest-library 的清单中。为此,需要将下面显示的指令元素添加到用于构建 p2 的 org.hamcrest.core 中“p2-maven-plugin”的执行配置中的 org.hamcrest:hamcrest-library 的工件元素中-repo:

pom.xml

如果使用 hamcrest-library 以外的 hamcrest 子模块,则指令需要类似,对应于其 pom 中列出的依赖项。

编辑 Eclipse Orbit 提供 <artifact> <id>org.hamcrest:hamcrest-library:1.3</id> <instructions> <Require-Bundle>org.hamcrest.core</Require-Bundle> </instructions> </artifact> org.hamcrest.libraryorg.hamcrest.integrator 捆绑包,这些捆绑包将 org.hamcrest.core 作为必需捆绑包(如有必要): https://download.eclipse.org/tools/orbit/downloads/

附录 最后第一个解决方案导致了 SecurityException:

org.hamcrest.generator

这是一个已知问题。以下两种解决方案可避免此问题,并在 Tycho 构建期间和在 Eclipse 中正常工作。

解决方案 2 - 使用插件捆绑 hamcrest 子模块 jar 另一种方法是下载所需 hamcrest 子模块的 jar 并将其直接与 Eclipse 插件捆绑,就像这里描述的那样: https://www.vogella.com/tutorials/Hamcrest/article.html#hamcrest_eclipse

要将 jar 与插件捆绑在一起,请将其包含在项目中并将其添加到插件类路径中。转到 Manifest-Editor 的 Runtime-Tab 并单击 Classpath 部分中的 java.lang.SecurityException: class "org.hamcrest.Matchers"'s signer information does not match signer information of other classes in the same package 并选择 jar。这应该将 jar 添加到 .classpath、MANIFEST.MF 和 build.properties 文件中。 确保 jar 包含在其他插件依赖项(包括 hamcrest-core)之前,如上述教程中所述。

如果 hamcrest 应该在多个测试项目/片段中使用,请将 jar 添加到所有其他测试项目所依赖的测试插件中。

解决方案 3 - 使用 org.hamcrest 2.x 由于 hamcrest-2 只有一个 org.hamcrest jar/artifact 包含来自 hamcrest 的所有内容。使用 hamcrest 2 避免了所有问题,是我首选的解决方案。除了更改了 hamcrest 的包装外,API 没有中断,因此只包含 org.hamcrest 就足够了: https://github.com/hamcrest/JavaHamcrest/releases/tag/v2.1

为了创建包含 Add...-2.2 的 p2-repo,以下 sippet 必须包含在 org.hamcrest 执行的 configuration-artifacts 元素中pom.xml:

p2-maven-plugin

必须将 IU <artifact> <id>org.hamcrest:hamcrest-core:2.2</id> <instructions> <Require-Bundle>org.hamcrest;bundle-version="2.2.0";visibility:=reexport</Require-Bundle> </instructions> </artifact> <artifact> <id>org.hamcrest:hamcrest:2.2</id> </artifact> 2.2 和 org.hamcrest.core 包含在目标平台中,才能使它们可用于 Eclipse 和 during 中的插件。所有依赖于 org.hamcrest 的插件现在也有 org.junit 可用。

这种方法有效,因为 org.hamcrest 仍然存在于第 2 版流中,即使它已被弃用且为空。它的唯一目的是将构建系统重定向到新的 org.hamcrest.core-2.x jar/artifact。因此 org.hamcrest-2.2 指定了一个编译依赖 org.hamcrest.core-2.2 在其 pom.xml 中。不幸的是,org.hamcrest 并没有直接将其转换为清单中 org.hamcrest 的捆绑需求,但上面的 sippet 强制执行了这一点。

因为 p2-maven-plugin 需要最低版本为 1.3(但没有上限)的 org.hamcrest.core 包,所以它使用当前的 org.junit-2.2 。 org.hamcrest.core-2.2 再次需要 org.hamcrest.core-2.2 并重新导出它。这使得 org.hamcrest 最后使用 org.junit-2.2 并且因为 org.junit 重新导出 org.hamcrest 它也立即为所有依赖的插件提供 hamcrest-core-2.2。< /p>

注意 如果您想使用 jar 的不同变体,请不要忘记清除(意味着在驱动器上删除)Maven(在 org.hamcrest 和 Eclipse PDE(在 <your-home>/.m2/repository/p2/osgi/bundle/)之间。否则你将永远使用第一个,因为相同版本的jar不会更新。