MOCKオブジェクトを使用したユニットテスト


mockテスト:テスト中に、構築しにくいオブジェクトや入手しにくいオブジェクトに対して、テストのためのテスト方法を仮想オブジェクトで作成します.
mockオブジェクト:この仮想オブジェクトがmockオブジェクトです.mockオブジェクトは、実際のオブジェクトのデバッグ中の代替品です.
mockオブジェクト使用カテゴリ:
1:真実の対象は不確定な行為を持ち、予測不可能な効果を生む(例えば:株価相場、天気予報)
2:リアルオブジェクトは作成しにくい
3:実際のオブジェクトのいくつかの動作はトリガーされにくい
4:リアルオブジェクトは実際には存在しません(他の開発チームや新しいハードウェアと付き合う)など...
mockオブジェクトテストのキーステップを使用します.
1:インタフェースを使用してオブジェクトを記述する
2:製品コードでこのインタフェースを実装する
3:テストコードでこのインタフェースを実装する
被テストコードではインタフェースのみでオブジェクトを参照するので、この参照オブジェクトが実際のオブジェクトなのかmockオブジェクトなのか分かりません.
1.何か問題がありましたか.
ユニットテストの目標は、1つの方法、小さなステップの前進、細粒度のテストだけを検証することですが、ネットワーク接続、データベース接続、サーブレットコンテナなど、他の操作しにくいものに依存している場合は、どうすればいいのでしょうか.
もしあなたのテストがシステムの他の部分、さらにシステムの複数の他の部分に依存していたら?この場合、うっかりすると、システムの各コンポーネントがほとんど初期化されていることに気づくかもしれませんが、これはテストに十分な実行環境を作って実行できるようにするためだけです.長い間忙しくて、私たちはテストの初心に少し背いているように見えます.これにより、時間を費やすだけでなく、テストプロセスにも多くの結合要素が導入されました.例えば、インタフェースやデータベースのテーブルを興味津々に変えた人がいるかもしれませんが、突然、あなたの卑しいユニットテストの神秘的な削除が行われました.このような状況が何度か発生した後、最も辛抱強い開発者でも気を落とし、最終的にすべてのテストを放棄することになるので、結果は想像できません.
さらに具体的な状況を見てみましょう.実際のオブジェクト向けソフトウェア設計では、現実のオブジェクトを構築した後、オブジェクト間は一連のインタフェースによって実現されることがよくあります.これはオブジェクト向けの設計で最も自然なことですが、ソフトウェアテストのニーズが発展するにつれて、小さな問題が発生します.例えば、ユーザーAは今、ユーザーBが提供するインタフェースを手に入れています.彼はこのインタフェースに基づいて自分のニーズを実現しましたが、ユーザーAが自分のコードをコンパイルした後、簡単にシミュレーションしてテストしたいのですが、どうすればいいですか.これも現実的な問題です.このインタフェースに対してエージェントクラスを簡単に実装し、シミュレーションをテストし、コードが自分の結果を生成することを期待することができますか?
幸いなことに、mockオブジェクトを助けるテストモードがあります.Mockオブジェクトは、実際のオブジェクトのデバッグ期間の代替品です.
2.今、モックオブジェクトは必要ですか?
いつMockオブジェクトが必要かについて、Tim Mackinnonはいくつかのアドバイスをしてくれました.
------実際のオブジェクトに不確定な行為がある(株の相場などの予測不可能な結果が生じる)
------実際のオブジェクトは作成しにくい(具体的なWebコンテナなど)
------実際のオブジェクトの動作によっては、ネットワークエラーなどのトリガが発生しにくい場合があります.
------プログラムの実行速度が遅い
------リアルオブジェクトにはユーザーインタフェースがあります
---テストでは、実際のオブジェクトがどのように呼び出されたかを尋ねる必要があります(たとえば、テストでコールバック関数が呼び出されたかどうかを検証する必要がある場合があります)
------実際のオブジェクトは存在しません(他の開発チームや新しいハードウェアシステムと付き合う必要がある場合、これは一般的な問題です).
3.Mockオブジェクトの実装方法
mockオブジェクトを使用してテストを行うには、次の3つのステップが必要です.
------インタフェースを使用してオブジェクトを記述します.
---製品コードのためにこのインタフェースを実現する
---テストを目的として、mockオブジェクトでこのインタフェースを実現
ここでまたインタフェースプログラミングの重要性を見ました.テストされたコードはインタフェースを通じてオブジェクトを参照するだけなので、実際のオブジェクトを参照しているのかmockオブジェクトを参照しているのか全く分かりません.次に、実際の例を見てみましょう.目覚まし時計は時間によって注意サービスを行います.午后5时を过ぎてオーディオファイルを再生して退勤するように注意して、もし私达が本当の対象を利用してテストするならば、苦労して午后5时まで待って、それから耳をスピーカーのそばに置くしかありません...私达はこんなに愚かではありませんて、私达はmockの対象を利用してテストを行うべきで、このように私达は时间をシミュレートすることができます時計が午後5時に回るのを待つ必要はありません.コードは次のとおりです.

public interface Environmental {  
  private boolean playedWav = false; 
  public long getTime();   
  public void playWavFile(String fileName); 
  public boolean wavWasPlayed();  
  public void resetWav();    
} 

実際の実装コード:

public class SystemEnvironment implements Environmental {  
  public long getTime() {    
  return System.currentTimeMillis();     
     }    
public void playWavFile(String fileName) {   
          playedWav = true;    
      }   
public boolean wavWasPlayed() {   
 return playedWav;       
   }    
public void resetWav() {    
         playedWav = false;    
      }    
} 

次はmockオブジェクトです.

public class MockSystemEnvironment implements Environmental {
 private long currentTime;  
  public long getTime() {  
     return currentTime;        
     }    
  public void setTime(long currentTime) {   
     this.currentTime = currentTime;        
     }    
  public void playWavFile(String fileName) {   
     playedWav = true;       
     }   
  public boolean wavWasPlayed() {  
      return playedWav;         
     } 
  public void resetWav() {  
      playedWav = false;      
     }   
 } 


次はgetTimeを呼び出す特定のクラスです.


import java.util.Calendar;   
public class Checker {   
private Environmental env;  
  public Checker(Environmental env) {
    this.env = env;   
       }    
  public void reminder() {    
         Calendar cal = Calendar.getInstance();             cal.setTimeInMills(env.getTime()); 
   int hour = cal.get(Calendar.HOUR_OF_DAY); 
   if(hour >= 17) {         
       env.playWavFile("quit_whistle.wav");       
      }   
       }   
 } 


env.getTime()を使用する被測定コードは、同じインタフェースが実装されているため、テスト環境と実際の環境の違いを知らない.これで、mockオブジェクトを使用して、時間を既知の値に設定し、動作が予想通りにテストされるかどうかを確認できます.


import java.util.Calendar; 
   import junit.framework.TestCase;
     public class TestChecker extends TestCase { 
  public void testQuittingTime() {                MockSystemEnvironment env = new MockSystemEnvironme();                Calendar cal = Calendar.getInstance();              
  cal.set(Calendar.YEAR, 2006);           
     cal.set(Calendar.MONTH, 11);          
      cal.set(Calendar.DAY_OF_MONTH,7);         
       cal.set(Calendar.HOUR_OF_DAY, 16);       
        cal.set(Calendar.MINUTE, 55);   
 long t1 = cal.getTimeInMillis();            
    env.setTime(t1);            
    Checker checker = new Checker(env);                checker.reminder();         
       assertFalse(env.wavWasPlayed());          
       t1 += (5*60*1000);         
       env.setTime(t1);      
          checker.reminder();   
             assertTrue(env.wavWasPlayed());                env.resetWav();              
  t1 += 2*60*60*1000;         
       env.setTime(t1);         
      checker.reminder();       
        assertTrue(env.wavWasPlayed());       
   } 
   } 


これがmockオブジェクトのすべてです.実際の世界を偽装するいくつかの行為は、自分のコードのテストに集中することができます.
4.トラブルがあるようです
毎回上記のように自分で具体的なmockオブジェクトを書くと、問題は解決しますが、トラブルがあるようで、焦らないでください.すでに第三者が作ったmockオブジェクトがあります.Mock Objectを使用してテストを行います.主に、HttpServletRequestがServletコンテナで構築されるようにアプリケーションで構築しにくいオブジェクトや、JDBCのResultSetオブジェクトのような複雑なオブジェクトをシミュレートしてテストを円滑に行うためのツールです.現在、Java陣営の主なMockテストツールはJMock、MockCreator、Mockrunner、EasyMock、MockMakerなどであり、マイクロソフトの.Net陣営では主にNmock、.NetMockなどである.
次に、EasyMockシミュレーションを使用してサーブレットコンポーネントをテストする例を示します.コードは次のとおりです.コンパイルしてTest Caseとして実行すると、両方のテスト方法がテストに成功します.easymockは、いくつかのservletコンポーネントのmockオブジェクトを実現するのに役立ち、webコンテナとservletコンテナから抜け出してservletを簡単にテストすることができます.


import org.easymock.*;  
  import junit.framework.*; 
   import javax.servlet.http.*;     
public class MockRequestTest extends TestCase{  
  private MockControl control;
    private HttpServletRequest mockRequest; 
   public void testMockRequest(){
    //    Mock HttpServletRequest MockControl   
         control = MockControl.createCo(HttpServletRequest.class);      
//    Mock HttpServletRequest         
   mockRequest = (HttpServletRequest) control.getMock();   
 //       Mock HttpServletRequest               mockRequest.getParameter("name");   
 //            ,        //               ,             
   control.setReturnValue("kongxx" ,1 ,1);        
   //  Mock HttpServletRequest   , 
//   Mock HttpServletRequest           
      control.replay();  
  //                 
 assertEquals("kongxx",mockRequest.getParameter("name")); 
   //              
   control.verify();  
       }    
} 

コンパイルしてTest Caseとして実行すると、両方のテストメソッドがテストに成功していることがわかります.easymockは、いくつかのservletコンポーネントのmockオブジェクトを実現するのに役立ち、webコンテナとservletコンテナから抜け出してservletを簡単にテストすることができます.
5.下位技術は何ですか.
ユーザーがC++とjavaのプログラムの生成を使用する場合、C++は最後の段階で接続してこそ全体のプログラムを生成することができ、これは柔軟性がjavaソースコードのメカニズムとは比べものにならない.javaの各クラスは独立しており、パッケージされたクラスも独立しており、ロードされてから接続されている.これはコードがロードされたとき、また、関連するビジネスニーズを挿入するなど、多くのアクションを実行することもできます.これもAOPの焦点です.javassitコードライブラリの実装はこれと似ています.これらを利用しているので、javaでMockオブジェクトを実装するのは簡単です.
6.関連するリソース
MockObjectのホームページhttp://www.mockobjects.com/重要なMock Objectの基本概念と現在の各環境における主要なMockテストツールを紹介した.
JMockのホームページhttp://www.jmock.org/JMockの最新コードと開発パッケージ、およびいくつかの説明ドキュメントを取得できます.
EasyMockのホームページhttp://www.easymock.org/JMockの最新コードと開発パッケージ、およびいくつかの説明ドキュメントを取得できます.
NMockのホームページhttp://www.nmock.org/Microsoft.NetプラットフォームでのMockテストの開発ツールを紹介した.