Webサービスを簡単にシミュレートする方法


SOA環境では、システムが他のシステムと対話することは避けられない.SOAPベースのWebサービス、RESTfulベースのWebサービス、メッセージキューベース、さらにはRPCベースのリモートコールであってもよい.システム依存の増加に伴い,単一システムのテストもますます困難になり,各システムをどのように効果的に隔離し,システムを個別にテストするか.
 
ここでは、Mockベースの簡単なテスト方法を紹介します!
 
開発過程でよく使われるテストにはユニットテストと統合テストがあり、以下にも2つの部分に分けて説明します.
もちろん、Webサービスをシミュレートするためのクラスを自分で実装することもできますが、本稿ではMockの開発をできるだけ多くしないようにする方法を選択しています.そのため、テストを支援するためにいくつかの補助ツールを選択します.
 
一、ユニットテスト中のMock
 
ユニットテスト自体は、被テストクラスとその依存性を分離する必要があり、被テストクラス自体の論理のみをテストする場合、いくつかのMockツールを選択してインタフェースをシミュレーションすることができます.合理的な設計が行われているかどうかは、ユニットテストの作成にも影響します.たとえば、「インタフェース向けプログラミング」のベストプラクティスに従うべきです.
 
Javaでよく使用されるMockフレームワークは、次のとおりです.
  • jMock( http://www.jmock.org/ )
  • EasyMock( http://www.easymock.org/ )
  • mockito( http://mockito.org/ )

  • 個人の好みで適当なフレームを選ぶことができます.本稿では、jMockを例に説明する.Webサービスのインタフェースの定義は次のとおりです.
     
    package mock.sample;
    
    /**
     *   
     */
    public interface SampleService {
        String operate(String str);
    }
    
     
    プロジェクトコードOperatorクラスではこのサービスを参照しており,戻り値を取得して以降の操作を行う必要がある.
    package mock.sample;
    
    /**
     * SampleService  
     */
    public class Operator {
        private SampleService sampleService;
    
        /**
         *  sampleService
         * 1、 result 5, str+result
         * 2、 result 5, result 
         */
        public String operate(String str) {
            String result = sampleService.operate(str);
            if (result != null && result.length() <= 5) {
                result = str + result;
            }
            return result;
        }
    
        public void setSampleService(SampleService sampleService) {
            this.sampleService = sampleService;
        }
    }
    
     
    ユニットテストを作成するときに、SampleServiceのオブジェクト注入Operatorをシミュレートします.jMockの使用については、jMockの『Getting Started』または『Cheat Sheet』を参照してください.jMockは主に録画再生方式を用い,予め所望の入出力を設定することでMockを実現する.
     
    package mock.sample;
    
    import static org.junit.Assert.assertEquals;
    
    import org.jmock.Expectations;
    import org.jmock.Mockery;
    import org.jmock.integration.junit4.JMock;
    import org.jmock.integration.junit4.JUnit4Mockery;
    import org.junit.Test;
    import org.junit.runner.RunWith;
    
    @RunWith(JMock.class)
    public class OperatorTest {
        private Mockery context = new JUnit4Mockery();
    
        @Test
        public void testOperate() {
            Operator operator = new Operator();
            final SampleService sampleService = context.mock(SampleService.class);
            operator.setSampleService(sampleService);
            context.checking(new Expectations() {
                {
                    oneOf(sampleService).operate("hi");
                    will(returnValue("HelloWorld!"));
    
                    oneOf(sampleService).operate("hello");
                    will(returnValue("world"));
                }
            });
    
            assertEquals("HelloWorld!", operator.operate("hi"));
            assertEquals("helloworld", operator.operate("hello"));
        }
    }
    
     
    ユニットテストでは,外部システムの論理を符号化経路で直接jMockでシミュレートし,トラフィックコードは,実際のWebサービスが呼び出されたのか,Mockオブジェクトが呼び出されたのかに注目しない.同様に,DAOなどの依存についても同様の方法でシミュレーションを行うことができる.
     
    二、集積テスト中のMock
     
    統合テストでは、XFire(または他のWebサービスフレームワーク)で導入されたクライアントではなくSpringコンテキストでMockのBeanをロードするなど、プログラミングによってMockを実現することもできます.しかし、この方法は煩雑であり、Mockクラスの戻り結果を変更する場合は、コードを変更してパブリケーションを再コンパイルする必要がある場合があります.さらに、オンラインでテストした構成から本番構成に戻すのを忘れてしまうと、大きな問題が発生します.
     
    もちろん、実際のサービスプロバイダを導入することもできますが、さまざまな理由で良い選択ではありません.
     
    Webサービスをテストする際、soapUIを使ったことがある人も多いと思いますが、soapUIを使ってWebサービスを呼び出すことに限られていますが、実は強力なsoapUIはMockサービスも可能で、事前の構成(Groovyスクリプト、XPathマッチング、順序、ランダムなどの方法)によって異なる結果を返すことができます.その実現原理は簡単に言えば、所与のWSDLシミュレーションWebサービスに基づいて、要求を受信した後、構成解析要求に従って、予め設定された結果を返し、ここでの要求と応答はいずれも標準的なSOAPメッセージである.
     
    簡単な実装手順は次のとおりです.
  • 新しいsoapUIプロジェクトを作成し、[New soapUI Project]ダイアログボックスにWSDLアドレスを入力し、[Create MockService]を選択します.
  • 「Generate MockService」ダイアログ・ボックスでシミュレーションするアクションを選択し、PathとPortはできるだけ実際のターゲット・サーバと一致します.たとえば、WSDLをパブリッシュするパスはhttp://xxx:8080/services/sampleService?wsdlでは、Pathは/services/cardInfoServiceで、Portは8080です.
  • 応答SOAPメッセージおよび戻り論理を編集する.

  • MockServiceの各メソッドを右クリックすると、MockOperation Editorにアクセスするか、新しいMockResponseを直接作成できます.MockServiceが作成されると、各操作にResponseがあり、ルールが設定されていない場合、これがデフォルトの応答です.
     
    1つのResponseのみを使用して、複数の呼び出しで異なる結果が必要な場合に手動で変更できますが、これは「自動化」されず、soapUIの割り当てメカニズムによって自動的にルールに従って対応する結果を返すことができます.
     
    SOapUIがサポートする配布メカニズム(詳細はMockOperations and Responses参照)は、次のとおりです.
  • SCRIPT、Groovyスクリプトを使用します.
  • SEQUENCEは、MockResponseが追加した順に1つずつ戻ります.
  • QUERY-MATCHは、要求内容に基づいて適切な結果を選択して返される.XPathパスとそのノードの期待値を指定し、一致すると対応するResponseを返します.
  • XPATHは、QUERY-MAATCHと同様に、XPathノードの値が返されるMockResponseの名前です.
  • RAM DOM、ランダムに戻ります.

  • 個人的にはXPATHとQUERY-MATCHの2つの割り当てメカニズムは複雑な場合に使いやすいと考えられており,これ以上複雑であればSCRIPTを考慮することができる.XPATHを例にとると、要求メッセージは以下のように仮定される.
     
    <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:fac="http://sample.mock.SampleService">
       <soapenv:Header/>
       <soapenv:Body>
          <fac:operate>
             <fac:in0>hi</fac:in0>
          </fac:operate>
       </soapenv:Body>
    </soapenv:Envelope>

     
    「hi」と「hello」という名前の2つのMockResponseを設定できます.エディタで「XPATH」を選択し、次のXPATHを設定します.
    declare namespace fac='http://sample.mock.SampleService'
    //fac:in0

    //fac:in 0の値が「hi」の場合、「hi」という名前のMockResponseが返されます.「hi」MockResponseコンテンツ:
     
    <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:fac="http://sample.mock.SampleService">
       <soapenv:Header/>
       <soapenv:Body>
          <fac:operate>
             <fac:out>HelloWorld!</fac:out>
          </fac:operate>
       </soapenv:Body>
    </soapenv:Envelope>
     
    QUERY_を使うとMATCHは、XPathのほかに、「hi」や「hello」などの「Expacted Value」を記入し、「Dispatch to」で適切なMockResponseを選択します.
     
    プロジェクトでは,WebサービスのEndpointアドレスを構成可能にするだけで,テストと生産環境のEndpointを容易に調整でき,Mockとリアルサーバの切り替えを実現できる.
     
    Mockを使用すると、テストのコストを大幅に削減できます.So、行こう~