4

Maven なしで RCP-Eclipse-Application をテストするために、Eclipse で JUnit-Tests を作成しています。一部のテストケースでは、Powermock (Easymock を使用) を使用して、オブジェクトの作成と静的メソッドをモックする必要があります。

testet となるクラスを含むプラグインと、対応するテストを含む 2 番目のプラグインがあります。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 からリンクされています。

@RunWithの代わりに JUnit-Rule でブートストラップも使用しましたが、同じ ClassNotFoundException が発生します。問題は変わりませんでした。

Plugin-Test の実行構成の再構成、マニフェストでの ClassPath: .\ の設定、PluginTest と Test.Util-Plugin の Lazy/Not-Lazy Loading と Buddy-ClassLoading の設定など、多くのことを試しました。

Webで何時間も試して検索した後、テストプラグインから3番目のプラグインに抽出された場合にPowermockがこの例外につながる理由と、これを機能させる方法はまだわかりません. アプリケーションで何かが誤って構成されているかどうかは、現時点ではわかりません。

同じまたは類似の問題に遭遇した人、またはそれに対する適切な解決策を得た人はいますか?

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 としてエクスポートするだけです。

更新: Chriss の質問に対する回答:

興味深いことに、PowerMock がエクスポートされたクラスしか操作できない理由を説明できますか? 私の現在の理解では、実行時にすべてのパッケージが表示され、ビルド/コンパイル時にのみ重要です。

Class.forName() を使用して OSGI でクラス ランタイムを取得する場合、バンドル クラスローダーを使用して名前のクラスを取得します。このバンドル クラスローダーは、インポートされたパッケージにあるクラスのみを認識します。Powermock バンドルには動的インポートがありますが、Powermock バンドルのクラスローダーは、任意のバンドルのエクスポートされたパッケージからのクラスのみを認識します。

クラスがどこから来て、どのバンドルがそれをエクスポートするかがわかれば、そのバンドルのクラスローダーを取得でき、そのクラスローダーから検索されたクラスを取得できます。しかし、これはもちろん非常に複雑であり、Powermock バンドルには、この詳細を隠すハッキーな魔法のクラスローダーが必要になることを意味しますが、そのようなものは存在しません。

詳細については、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 に答える