どのようにサーバー側から複雑なREST呼び出しを模擬するか?

GET、PUT、POST、DELETESなどのようなボキャブを使用することを含め、RESTサービスを広範囲に使用するjavascriptを使用している間、私は、フロント側の開発が独立して(バックエンドの)続けることができるように、サーバ側を模擬するのは難しいことが分かっています。

時には多段階のデータを取り込むことも有益であるため、RESTのチェーン全体(またはこれらのチェーンからトリガーされるフロントエンドに関するバグ)を再現するのに役立ちます。

どのようなツールを使ってREST呼び出しをモックすることができますか? (つまり、一部のリソースでPUTを実行すると、その次のGETが何とか変更されることが期待されます)

私はSOAPUI 4.0.1を試しました。それはRESTの嘲笑は残念です。さらに、私の必要性は、単一の状態の嘲笑(誰でも静的な.jsonファイルで行うことができる)を超えています。私はモックの状態遷移型を行う必要があります。 Content-Rangeヘッダーを使用するのが最適です。

誰でも?

7

2 答え

ここに自家製のレストモッキングツールがあります: https://github.com/mkotsur/restito

3
追加された

私は実際には自分のJava REST Mock Engineを作成してしまいました。 HTTPレスポンス全体をシミュレートするテキストファイルを手作業またはカットペーストすることができれば、私のソリューションを使ってサービスを模擬することができます。

ここにサーブレットがあります:

package com.mockrest.debug;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.util.Arrays;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.servlet.GenericServlet;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

/**
 * Servlet implementation class MockGridData
 */
public class MockRest extends HttpServlet {
    private static final long serialVersionUID = 1L;

    /**
     * @see HttpServlet#HttpServlet()
     */
    public MockRest() {
        super();
       //TODO Auto-generated constructor stub
    }

    @Override
    public void service(ServletRequest req, ServletResponse res)
            throws ServletException, IOException {
        sub:{
            HttpServletRequest request = (HttpServletRequest)req;
            HttpServletResponse response = (HttpServletResponse)res;
            String setdata = request.getParameter("__setdata");
            if (setdata!=null && setdata.length()>0){
                System.err.println("Setting Data...");
                HttpSession sess = request.getSession(true);
                String data = "/"+request.getParameter("__setdata");
                sess.setAttribute("data", data);
                try{
                    InputStream is = getServletContext().getResourceAsStream(data);
                    if (is!=null){
                        is.close();
                        response.getWriter().write("Successfully pointed next REST call to:"+data);
                    }
                    else{
                        response.sendError(500, "Cannot find resource:"+data);
                    }
                }
                catch (IOException ioe){
                    response.sendError(500, Arrays.deepToString(ioe.getStackTrace()));
                }

            }
            else{
                System.err.println("Fetching Data...");
                HttpSession sess = request.getSession(false);
                if (sess==null || sess.getAttribute("data")==null){
                    response.sendError(500,"Session invalid or no Previous Data Set!");
                }
                String rsrc = (String)sess.getAttribute("data");
                System.err.println("Resource Being used:"+rsrc);
                InputStream is = getServletContext().getResourceAsStream(rsrc);
                if (is!=null){
                    String statusline = readLine(is);
                    Pattern statusPat = Pattern.compile("^HTTP/1.1 ([0-9]+) (.*)$");
                    Matcher m = statusPat.matcher(statusline);
                    if (m!=null && m.matches()){
                        int status = Integer.valueOf(m.group(1));
                        response.setStatus(status, m.group(2));
                    }
                    else{
                        throw new ServletException("Bad input file: status line parsing failed, got this as status line:"+statusline);
                    }
                    String line;
                    Pattern httpHeaderPat = Pattern.compile("^([^:]+): (.*)$");
                    while ((line=readLine(is))!=null){
                        if (line.length()==0){
                           //end of headers
                            break;
                        }
                        Matcher m2 = httpHeaderPat.matcher(line);
                        if (m2!=null && m2.matches()){
                            response.setHeader(m2.group(1), m2.group(2));
                        }
                    }
                    OutputStream os = response.getOutputStream();
                    byte[] buf = new byte[1024];
                    int size;
                    while ((size=is.read(buf))>0){
                        os.write(buf, 0, size);
                    }
                    os.flush();
                }
            }
        }
    }

    private String readLine(InputStream is) throws IOException {
        StringBuffer sb = new StringBuffer();
        char c;
        while ((c=(char)is.read())!='\n'){
            sb.append(c);
        }
        if (sb.charAt(sb.length()-1) == '\r'){
            sb.deleteCharAt(sb.length()-1);
        }
        return sb.toString();
    }

}

それを設定するには、 WebContent フォルダの中にあらかじめ作成されたレスポンスファイルを置きます。私は通常これらのファイルを .http 拡張子で終了します。

init.http ファイルの例を以下に示します。このファイルをWebContent内の data というフォルダの中に置いたふりをしてみてください。

HTTP/1.1 200 OK
Date: Wed, 26 Oct 2011 18:31:45 GMT
Server: Microsoft-IIS/6.0
X-Powered-By: ASP.NET
X-AspNet-Version: 4.0.30319
Content-Range: items 0-1/2
Content-Length: 385
Cache-Control: private
Content-Type: application/json

[
  {
    "id": "249F0",
    "field1": " Global",
    "displaystartdate": "2007-10-20",
    "displayenddate": "2012-10-20",
    "status": "Major Delay",
    "children": true
  },
  {
    "id": "962581",
    "field2": "Europe",
    "displaystartdate": "2007-10-20",
    "displayenddate": "2012-10-20",
    "status": "Major Delay",
    "children": true
  }
]

ヘッダーは本文と空白で区切られている必要があります(スペースなし、nada)。 httpに精通している人は、それが純粋なhttpレスポンスであることに気づくでしょうこれは目的上のものです。

このツールを使用して、レスポンスに必要なhttpヘッダーをシミュレートすることができます。これまでのところ、別のサーバーヘッダーで応答するようになっています(私の例では、IIS 6.0であると思われる応答をシミュレートしました)。または異なるHTTPステータスコードなど

あなたのブラウザ/ javascriptからそれを呼び出す。最初にそれをプライムしてください:

http://yourserver/yourweb/MockGridData?__setdata=data/init.http

その後、あなたのJavaScriptまたはREST AJAX呼び出しで、もしそれが行くなら

http://yourserver/yourweb/MockGridData

任意の方法またはパラメータで;これまでに作成したhttpレスポンスを取得します。 Content-Rangeまで下がっています。キャッシュヘッダー。その後、別のものを返すために後続のAJAX呼び出しが必要な場合は、 __setdata を再度呼び出してください。私はあなたのWebアプリケーションで明示的な状態遷移を行うためのいくつかのボタンを設定することをお勧めします。

シミュレートされたRESTチェーンのために、すべてがセットアップされていると仮定すると、開発者は次の操作を実行できます。

  1. invoke

    http://yourserver/yourweb/MockGridData?__setdata=data/init.http
    
  2. run a JavaScript module that will result in calling (say, with GET)

    http://yourserver/yourweb/MockGridData
    
  3. click a button that then does:

    http://yourserver/yourweb/MockGridData?__setdata=data/step1.http
    
  4. run another JavaScript step that will result in calling (say, with PUT)

    http://yourserver/yourweb/MockGridData
    
  5. click another button that then does:

    http://yourserver/yourweb/MockGridData?__setdata=data/step2.http
    
  6. run another JavaScript step that will result in calling (say, with GET)

    http://yourserver/yourweb/MockGridData
    

    but this time expecting different result than #4.

これは、バイナリとgzipされた応答でも動作するはずですが、私はそれをテストしていません。

2
追加された
ソリューションをおめでとう。あなたができるときは、あなたの答えを「受け入れられた」とマークして、他の人があなたの成功から学ぶかもしれないようにしてください。乾杯〜
追加された 著者 Andrew Kozak,