2009-07-29 6 views
15

Javaで静的メソッドを簡単に模倣するにはどうすればよいですか?Javaで静的メソッドを簡単に模倣する方法(jUnit4)

私はので、私はリファクタリング、それはより多くのユニット・テストが可能であることをすることはできません私のサービスを呼び出す必要がある静的メソッドをコントロールしていない春2.5とJUnit 4.4

@Service 
public class SomeServiceImpl implements SomeService { 

    public Object doSomething() { 
     Logger.getLogger(this.class); //a static method invoked. 
     // ... 
    } 
} 

を使用しています。私は例としてLog4J Loggerを使用しましたが、実際の静的メソッドは似ています。 静的メソッドを変更することはできません。私はJavaで似た何かをするにはどうすればよい

def mockedControl = mockFor(Logger) 
mockControl.demand.static.getLogger{Class clazz-> … } 
… 
mockControl.verify() 

Grailsの作業をやって、私は次のようなものを使用して使用していますか?

+0

SomeServiceImpl実装を変更できますか? –

+0

心配しないで、Jon Skeetはちょうど私が思ったことを投稿しました。私は誇りに思う! (Jon Skeet heheのように思う) –

+0

はい私はSomeServiceImplを変更することができますが、どうすればいいですか?なぜ間接的な間接化ですか? –

答えて

0

Java + Spring 2.5でこれを行う簡単な方法はありません&現時点ではJUnit 4.4です。

リファクタリングして静的呼び出しを抽象化することは可能ですが、コードのリファクタリングは私が探していた解決策ではありません。

JMockitは動作するように見えましたが、Spring 2.5およびJUnit 4.4と互換性がありません。

+2

PowerMockが提案されており、静的メソッドをモックすることができるので、簡単な方法があります。 – Richard

+0

PowerMockには重大なメモリリークがあります。これは、Mavenプラグインを使用したときのJenkinsビルドのメモリ使用量と期間、ユニットテストを自動的に実行してビルド品質を保証します。これがPowerMockが悪い選択肢である理由です。 – Igor

+0

これをチェックして、https://blog.jayway.com/2014/11/29/using-another-junit-runner-with-powermock/ @RunWith(PowerMockRunner.class)を実行してから@PowerMockRunnerDelegate(SpringJUnit4ClassRunner)に委任できます。 。クラス)。もちろん、これにはいくつかの最新バージョンで作業する必要があります。 – Yasin

14

呼び出しコードを制御できないのですか? からへの呼び出しを制御すると、実装自体ではなく静的メソッドが制御されるので、簡単にそのテスト可能にすることができます。静的メソッドと同じシグネチャを持つ単一のメソッドを使用して、依存関係インタフェースを作成します。プロダクション実装は静的メソッドを呼び出すだけですが、現在静的メソッドを呼び出すものは、代わりにインターフェイス経由で呼び出します。

これで、そのインターフェイスを通常の方法でモックアウトできます。

1
public interface LoggerWrapper { 
    public Logger getLogger(Class<?> c); 
    } 
public class RealLoggerWrapper implements LoggerWrapper { 
    public Logger getLogger(Class<?> c) {return Logger.getLogger(c);} 
    } 
public class MockLoggerWrapper implements LoggerWrapper { 
    public Logger getLogger(Class<?> c) {return somethingElse;} 
    } 
0

これは静的メソッドが悪い理由の1つです。

ほとんどの私たちの工場では、モックオブジェクトを設定できるように、セッターも持っています。実際、単一のメソッドがすべてのシングルトンのファクトリとして機能する依存関係注入に近いものを考え出しました。

あなたのケースでは、Logger.setLogger()メソッドを追加(およびその値を保存)することができます。必要がある場合は、ロガークラスを拡張し、getLoggerメソッドを自分自身でシャドウすることもできます。

4

JMockitフレームワークは、静的メソッドのモックを許可することを約束します。

https://jmockit.dev.java.net/

実際には、それが静的メソッドは完全に有効な設計上の選択であり、その使用が原因でテストフレームワークの不備により限定されるものではないことを含め、いくつかのかなり大胆な主張を作ります。

このようなクレームが正当なものであるかどうかにかかわらず、JMockitフレームワーク自体はかなり面白いですが、私はまだそれを試していません。

+1

静的メソッドの使用は常に議論の余地があります。しかし、誰でも実際にfinalキーワードの賢明な使用に反対して論争することはできますか?たとえば、「効果的なJava」の本が何を言いたいのか(項目17)を考えてみましょう。 –

+1

JMockitを使用すると、Spring 2.5.xがJUnit 4.5+と互換性がなく、JMockitがJUnit 4.4(以下)と互換性があることが判明しました。http://jira.springframework.org/browse/SPR-5145を参照してください。 via http://stackoverflow.com/questions/693115/junit4-spring-2-5-asserts-throw-noclassdeffounderror –

+0

だから、JMockitは今のところ問題にはなりません。 –

0

AspectJを使って静的メソッド呼び出しをインターセプトし、テストに役立つ何かを行うことができます。

+1

どうすればいいですか?簡単な例はありますか? –

1

前述の別の回答として、JMockitは静的メソッド(および他のものも同様)をモックできます。

ロギングフレームワークを直接サポートしています。たとえば、次のように書くことができます。


@UsingMocksAndStubs(Log4jMocks.class) 
public class SomeServiceTest 
{ 
    // All test methods in this class will have any calls 
    // to the Log4J API automatically stubbed out. 
} 

ただし、JUnit 4.4のサポートは廃止されました。 JUnit 3.8、JUnit 4.5+、TestNG 5.8+がサポートされています。

4

PowerMockこの能力があります。テスト中のクラス内ののオブジェクトのインスタンス化を模擬することもできます。テストしたメソッドが新しいFoo()を呼び出す場合は、そのFooのモックオブジェクトを作成し、テストしているメソッドでそれを置き換えることができます。

抑制コンストラクタや静的初期化子のようなものも可能です。これらのすべてのものはテストされていないコードと見なされるため、推奨されませんが、レガシーコードをお持ちの場合、変更することは必ずしもオプションではありません。そのポジションにいる場合はPowerMockがお手伝いします。

関連する問題