15

私は長年 EasyMock のファンであり、SO のおかげで、PowerMock への参照に出くわし、コンストラクターと静的メソッドをモックする機能に出会いました。どちらも、テストをレガシー コードベースに後付けするときに問題を引き起こします。

明らかに、単体テスト (および TDD) の大きな利点の 1 つは、それが (力?) よりクリーンな設計につながる方法であり、PowerMock の導入はそれを損なう可能性があるように私には思えます。これは主に次のように現れます。

  1. コラボレーターを注入するのではなく初期化することに戻る
  2. メソッドを共同作業者が所有するのではなく、静的を使用する

これに加えて、自分のコードがテスト用にバイトコードで操作されていることについて、何かがうまくいきません。具体的な理由は言えませんが、本番用ではなくテスト用なので少し不安です。

私の現在のギグでは、人々がコーディングの実践を改善する方法として、単体テストを本当に推進しています. PowerMock を方程式に導入すると、人々はそのステップをいくらかスキップできるようになるので、私はそれを使い始めるのが嫌です. そうは言っても、それを利用することで、クラスのテストを開始するために必要なリファクタリングの量をどこで削減できるかがよくわかります。

私の質問は、これらの機能に PowerMock (または他の同様のライブラリ) を使用した人々の経験は何ですか?それらを利用しますか?また、テストが設計にどの程度影響を与えることを望んでいますか?

4

6 に答える 6

15

私はこの質問に強く反対しなければなりません。

設計の選択肢を制限するモッキング ツールを正当化する理由はありません。EasyMock、EasyMock クラス拡張、jMock、Mockito などによって除外されるのは静的メソッドだけではありません。これらのツールはまた、クラスとメソッドを宣言することを妨げますがfinal、それだけでは非常に悪いことです。(for クラスとメソッドの使用を擁護する信頼できる情報源が 1 つ必要な場合finalは、「Effective Java」の本を参照するか、著者によるこのプレゼンテーションをご覧ください。)

そして、私の経験では、「コラボレーターを注入するのではなく、初期化する」ことが最良の設計であることがよくあります。そのクラスからインスタンス化されるヘルパー クラスを作成することによって、複雑な問題を解決するクラスを分解する場合、特定のデータをそれらの子オブジェクトに安全に渡す機能を利用でき、同時にそれらをクライアント コードから隠します (高レベル操作で使用される完全なデータを提供します)。パブリック API でこのようなヘルパー クラスを公開すると、情報隠蔽の原則に違反し、カプセル化が破られ、クライアント コードが複雑になります。

DI を悪用すると、実際にはステートフルである必要があるステートレス オブジェクトが生成されます。これらのオブジェクトは、ほとんどの場合、ビジネス オペレーションに固有のデータを操作するためです。これは、非公開のヘルパー クラスだけでなく、UI/プレゼンテーション オブジェクトから呼び出される公開の「ビジネス サービス」クラスにも当てはまります。このようなサービス クラスは通常、(単一のビジネス アプリケーションに対する) 内部コードであり、本質的に再利用可能ではなく、数個のクライアント (多くの場合 1 つだけ) しかありませ。このような場合 (ちなみに、非常に一般的なケースです)、UI クラスでビジネス サービス クラスを直接インスタンス化し、ユーザーから提供されたデータをコンストラクターを介して渡す方がはるかに理にかなっています。

このようなコードの単体テストを簡単に記述できることが、まさに JMockitツールキットの作成につながったのです。私が考えていたのはレガシー コードではなく、デザインのシンプルさと経済性です。これまでに達成した結果から、テスト容易性は実際には 2 つの変数の関数であることがわかりました。それは、運用コードの保守容易性と、そのコードのテストに使用されるモック ツールの制限です。では、モッキング ツールからすべての制限を取り除くと、何が得られるでしょうか?

于 2009-06-29T01:32:16.220 に答える
13

テスト容易性が最終目標ではないことに完全に同意します。これは、PowerMock を開発するときに気付いたことの 1 つです。また、単体テストを作成することが優れた設計を実現する 1 つの方法であることにも同意します。PowerMock の使用は、少なくともコンストラクターに対する期待や静的モッキングなどの機能については、ルールではなく例外である必要があります。

PowerMock を使用する主な理由は、コードのテストを妨げるサード パーティ コードを使用する場合です。良い代替手段は、サードパーティのコードを抽象化してテスト可能にする腐敗防止レイヤーを使用することです。ただし、標準 API を使用するだけでコードがよりクリーンになると思うことがあります。これの良い例は、Java ME API です。これは、単体テストを妨げる静的メソッド呼び出しでいっぱいです。

レガシ コードでも同じ問題が発生する可能性があります。一部の組織は、既存のコードを変更することを非常に恐れています。この場合、PowerMock を使用して、大規模なリファクタリングを強制することなく、現在作成している部分に単体テストを導入できます。

私たちの問題は、新人開発者が従うことができる、PowerMock を使用するかどうかの一連のベスト プラクティス ルールを指定することです。優れたデザインを作成するのは非常に難しく、PowerMock はより多くのオプションを提供するため、初心者にとっては難しくなるだけでしょうか? より経験豊富な開発者は、より多くの選択肢があることを高く評価していると思います。

( PowerMockの創設者)

于 2009-01-15T10:17:23.613 に答える
5

私はあなたが正しいと思います.PowerMockが必要な場合は、おそらくコードが臭いです. それらの静的を取り除きます。

ただし、バイトコードの計測については間違っていると思います。私は常にmockitoを使用して具象クラスをモックアウトしています。これにより、すべてのインターフェイスを作成する必要がなくなります。独身。クラス。それははるかにきれいです。

コードの臭いを防ぐことができるのはあなただけです。

于 2009-01-09T14:11:06.767 に答える
4

Typemock Isolator に関して、.NET 分野でも同じ質問が多数寄せられています。このブログ投稿を参照してください

テスト容易性が最終目標ではなく、設計は別の方法で学習されることに人々が気づき始めたとき、どのツールを使用するかを恐れに任せたり、より高度な技術が必要になった場合に使用しないようになると思います。関連する。

また、アプリケーションのニーズに基づいて、設計方法を選択できることも理にかなっています。ツールに設計方法を教えさせないでください。選択の余地はありません。

(私は Typemock で働いていますが、一度反対されました)

于 2009-01-09T21:09:24.020 に答える
3

私はあなたが心配するのは正しいと思います。レガシーコードをテスト可能にリファクタリングすることは、方法を学んだ後はほとんどの場合それほど難しくありません。

近道をして悪い習慣を学ぶよりも、少しゆっくりと進み、学習を支援する環境を整える方がよいでしょう。

(そして私はこれを読んで、それが関連しているように感じます。)

于 2009-01-09T13:00:16.877 に答える
0

リフレクションに対して Powermock が提供する抽象化のレイヤーは魅力的に見えますが、テストが脆弱になります。すなわち:

  1. リフレクションは、メソッド/フィールドなどの文字列名に依存しています。名前を変更すると、テストが中断され、その後、リフレクションを通じてこのメソッドにアクセスするすべてのテストが修正されます。リフレクションを必要としないテストと比較して、すべての名前変更は IDE によってリファクタリングされます。
  2. スタブ、静的メソッド呼び出しなどの Powermock の機能によりnew、関数の実装の詳細を調べることができます。テストは理想的には機能をテストする必要があります。

    functionOldImplementation(){
        List l = new ArrayList();
    }
    // old implementation changed to new
    functionNewImplementation(){
        List l = new LinkedList();
    }
    

呼び出しをモックするnew ArrayList()と、上記のリファクタリングのテストが中断されます。リグレッションを実行するにはテストが最も必要であり、この方法で実行すると失敗します。

最近、この記事に出くわしました。質問で尋ねられたポイントのほとんどに対処しているので、共有したいと思います。

記事の重要なポイント:

  1. PowerMock + Javaassist が Java7 に対応するまでには、導入から 1.5 年かかりました。PowerMock 変更ログからのメモは次のとおりです。

    Change log 1.5 (2012-12-04)  
    ---------------------------     
    Upgraded to Javassist 3.17.1-GA, this means that PowerMock works in Java 7!
    
  2. PowerMock サイトは次のように述べています。

「PowerMock は、主に単体テストの専門知識を持つ人々を対象としていることにご注意ください。ジュニア開発者の手に渡すと、利益よりも害が生じる可能性があります」.

于 2016-09-25T22:16:21.850 に答える