4

我正在 Eclipse 中编写 JUnit-Tests 来测试没有 Maven的 RCP-Eclipse-Application 。对于某些测试用例,必须使用 Powermock(使用 Easymock)来模拟对象创建和静态方法。

我有一个包含应该是 testet 的类的插件和包含相应测试的第二个插件。让我们捐赠它们 PluginObject 和 PluginTest:

工作情况:

* PluginObject
  - src 
      - ClassUnderTest

* PluginTest
 - src
     - TestCase
 - lib
     - easymock
     - powermock
     - ... [aditional classes (like JavaAssist)]

使用 PLuginTest 中带有 powermock-Jar 的配置,TestCase 和 Plugins-Manifest-Runtim 中的配置运行正常并返回所需的结果。

我的 TestCase 从以下几行开始,当前使用@RunWith -Annotation:

@RunWith(PowerMockRunner.class)
@PowerMockIgnore({ "javax.management.*", 
"javax.xml.parsers.*",
"com.sun.org.apache.xerces.internal.jaxp.*",
"javax.xml.*",
"ch.qos.logback.classic.*",
"org.slf4j.*",
"org.eclipse.core.runtime.jobs.ISchedulingRule" })
@PrepareForTest    ({Controller.class,ProcessLoaderFactory.class,Engine.class,CommandCollector.class})
@SuppressStaticInitializationFor({"Controller","   ProcessLoaderFactory","Engine","CommandCollector"})
public class ControllerTest {
...
[skipped package information due to copyrights]

但是我有多个插件想要在我的应用程序中使用 Powermock 进行模拟,这对我来说将共享库提取到另一个特殊插件似乎是个好主意 - 我们称之为 Test.Util:

* PluginObject
  - src 
      - ClassUnderTest

* PluginTest
 - src
     - TestCase

* Test.Util
 - lib
     - easymock
     - powermock
     - ... [aditional classes (like JavaAssist)]

对于除 Powermock 之外的所有其他库,我没有任何问题,但是当我将 Powermock 从 PluginTest 移动到 Test.Util-Plugin 时,在启动 JUnit Plugin-Test 时初始化时出现“ClassNotFoundException”。(正常的 JUnit-Test 不会抛出此错误)

java.lang.ClassNotFoundException: xxx.yyy.zzz.MyTest
at org.eclipse.osgi.internal.loader.BundleLoader.findClassInternal(BundleLoader.java:513)
at org.eclipse.osgi.internal.loader.BundleLoader.findClass(BundleLoader.java:429)
at org.eclipse.osgi.internal.loader.BundleLoader.findClass(BundleLoader.java:417)
at org.eclipse.osgi.internal.baseadaptor.DefaultClassLoader.loadClass(DefaultClassLoader.java:107)
at java.lang.ClassLoader.loadClass(Unknown Source)
at org.powermock.core.classloader.MockClassLoader.loadModifiedClass(MockClassLoader.java:143)
at org.powermock.core.classloader.DeferSupportingClassLoader.loadClass(DeferSupportingClassLoader.java:67)
at java.lang.ClassLoader.loadClass(Unknown Source)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Unknown Source)
at org.powermock.modules.junit4.common.internal.impl.JUnit4TestSuiteChunkerImpl.createDelegatorFromClassloader(JUnit4TestSuiteChunkerImpl.java:133)
at org.powermock.modules.junit4.common.internal.impl.JUnit4TestSuiteChunkerImpl.createDelegatorFromClassloader(JUnit4TestSuiteChunkerImpl.java:39)
at org.powermock.tests.utils.impl.AbstractTestSuiteChunkerImpl.createTestDelegators(AbstractTestSuiteChunkerImpl.java:217)
at org.powermock.modules.junit4.common.internal.impl.JUnit4TestSuiteChunkerImpl.<init>(JUnit4TestSuiteChunkerImpl.java:59)
at org.powermock.modules.junit4.common.internal.impl.AbstractCommonPowerMockRunner.<init>(AbstractCommonPowerMockRunner.java:32)
at org.powermock.modules.junit4.PowerMockRunner.<init>(PowerMockRunner.java:31)
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(Unknown Source)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(Unknown Source)
at java.lang.reflect.Constructor.newInstance(Unknown Source)
at org.junit.internal.builders.AnnotatedBuilder.buildRunner(AnnotatedBuilder.java:31)
at org.junit.internal.builders.AnnotatedBuilder.runnerForClass(AnnotatedBuilder.java:24)
at org.junit.runners.model.RunnerBuilder.safeRunnerForClass(RunnerBuilder.java:57)
at org.junit.internal.builders.AllDefaultPossibilitiesBuilder.runnerForClass(AllDefaultPossibilitiesBuilder.java:29)
at org.junit.runners.model.RunnerBuilder.safeRunnerForClass(RunnerBuilder.java:57)
at org.junit.internal.requests.ClassRequest.getRunner(ClassRequest.java:24)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.<init>(JUnit4TestReference.java:33)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestClassReference.<init>(JUnit4TestClassReference.java:25)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestLoader.createTest(JUnit4TestLoader.java:48)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestLoader.loadTests(JUnit4TestLoader.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:452)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
at org.eclipse.pde.internal.junit.runtime.RemotePluginTestRunner.main(RemotePluginTestRunner.java:62)
at org.eclipse.pde.internal.junit.runtime.PlatformUITestHarness$1.run(PlatformUITestHarness.java:47)
at org.eclipse.swt.widgets.RunnableLock.run(RunnableLock.java:35)
at org.eclipse.swt.widgets.Synchronizer.runAsyncMessages(Synchronizer.java:135)
at org.eclipse.swt.widgets.Display.runAsyncMessages(Display.java:4140)
at org.eclipse.swt.widgets.Display.readAndDispatch(Display.java:3757)
at org.eclipse.ui.internal.Workbench.runEventLoop(Workbench.java:2696)
at org.eclipse.ui.internal.Workbench.runUI(Workbench.java:2660)
at org.eclipse.ui.internal.Workbench.access$4(Workbench.java:2494)
at org.eclipse.ui.internal.Workbench$7.run(Workbench.java:674)
at org.eclipse.core.databinding.observable.Realm.runWithDefault(Realm.java:332)
at org.eclipse.ui.internal.Workbench.createAndRunWorkbench(Workbench.java:667)
at org.eclipse.ui.PlatformUI.createAndRunWorkbench(PlatformUI.java:149)
at org.eclipse.ui.internal.ide.application.IDEApplication.start(IDEApplication.java:123)
at org.eclipse.pde.internal.junit.runtime.NonUIThreadTestApplication.runApp(NonUIThreadTestApplication.java:54)
at org.eclipse.pde.internal.junit.runtime.UITestApplication.runApp(UITestApplication.java:41)
at org.eclipse.pde.internal.junit.runtime.NonUIThreadTestApplication.start(NonUIThreadTestApplication.java:48)
at org.eclipse.equinox.internal.app.EclipseAppHandle.run(EclipseAppHandle.java:196)
at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.runApplication(EclipseAppLauncher.java:110)
at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.start(EclipseAppLauncher.java:79)
at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:344)
at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:179)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.eclipse.equinox.launcher.Main.invokeFramework(Main.java:622)
at org.eclipse.equinox.launcher.Main.basicRun(Main.java:577)
at org.eclipse.equinox.launcher.Main.run(Main.java:1410)
at org.eclipse.equinox.launcher.Main.main(Main.java:1386)

我在 MANIFEST.MF 的 Runtime 下的 Classpath 中配置了 Test.Util,并导出了这些插件的每个包。在 Eclipse 中,正确的库是从 TestCase 链接的。

我还使用带有 JUnit-Rule 而不是@RunWith的 Bootstrapping ,但它会导致相同的 ClassNotFoundException。问题没有改变。

我现在尝试了很多东西 - 重新配置插件测试的运行配置,在清单中设置 ClassPath: .\,延迟/非延迟加载以及为 PluginTest 和 Test.Util-Plugin 设置 Buddy-ClassLoading。

经过数小时的网络尝试和搜索,我仍然不知道为什么 Powermock 会导致此异常,如果它是从 Test-Plugin 提取到第三个插件中,以及我如何使这项工作正常工作。我目前不能说我的应用程序中是否有错误配置。

有谁遇到过相同或类似的问题,或者得到了很好的解决方案?

4

3 回答 3

3

“注册”政策对我没有帮助,我也不想用 util 插件注册每个插件。我的解决方案是在“Test.Util”中声明:

Eclipse-BuddyPolicy:依赖、注册、全局、应用

这使 PowerMockito 或多或少地可以使用所有类。

于 2012-11-23T16:41:35.197 回答
2

您需要一个具有正确 OSGI 清单和 OSGI 依赖项的 Powermock 版本。现在你可以试试我的小项目,其中包含 Powermock 1.5.4 的 P2 更新站点。请参阅https://code.google.com/p/powermock/OSGI部分(直接链接:https ://code.google.com/p/powermock-osgi )。

在 OSGI 环境中,您只能使用导出包中的 Powermock 操作类。在我的 P2 更新站点上,您会找到一个 Powermock,它具有:

Eclipse-BuddyPolicy: global,ext,boot

这基本上意味着 Powermock 可以访问任何导出的包。您仍然必须导出经过测试的包。如果您不想公开所有捆绑包的包,您仍然可以在清单中使用X-Friends指令。您使用 Powermock 将包导出为 X-Friend,仅此而已。

更新: 回答克里斯的问题:

有趣的是,你能解释一下为什么 PowerMock 只能操作导出的类吗?我目前的理解是,在运行时所有包都是可见的,只有在构建/编译时才重要。

如果你使用 Class.forName() 来获取 OSGI 中的类运行时,你将使用你的包类加载器来获取你的名字的类。这个包类加载器只看到导入包中的类。Powermock 包具有动态导入,但 Powermock 包的类加载器仍然只能看到任何包的任何导出包中的类。

如果您知道您的类来自哪里,哪个包将其导出,那么您将能够获取该包的类加载器,并从该类加载器中获取搜索到的类。但这当然很复杂,这意味着 Powermock 包需要一些 hacky 魔术类加载器,它隐藏了这个细节,但这样的东西不存在。

有关详细信息,请参阅http://olegz.wordpress.com/2008/11/05/osgi-and-classforname/

更新: Powermock-osgi 现在托管在 github 上。https://github.com/liptga/powermock-osgi

更新站点:https ://raw.githubusercontent.com/liptga/powermock-osgi/master/update-site/1.5.6.0

于 2014-02-17T08:13:55.667 回答
1

我已经删除了我之前的评论,因为我成功地设法使用存储在单个插件中的 PowerMock 库运行 pde 插件测试。要使用您的示例回答您的问题,您需要在您的 Test.Util 中添加以下行(您不应使用大写的插件 ID)MANIFEST.MF

Eclipse-BuddyPolicy: registered

然后,如果您使用 PluginTest 插件是一个普通插件,则在它的 MANIFEST.MF 中添加以下行

Eclipse-RegisterBuddy: Test.Util

如果您的 PluginTest 是包 PluginObject 的一个片段,那么您必须在作为 PluginObject 清单的主机包中添加上一行。希望这可以帮助 ;)

于 2012-06-07T09:17:01.880 回答