存根/虚拟一个宁静的网络服务的简单方法是什么?

发布于 2024-12-25 14:17:01 字数 175 浏览 0 评论 0原文

我想创建一个 Android 应用程序,该应用程序将对 Web 服务进行 RESTful 调用以获取一些数据。

我知道 RESTful 接口是什么,但我不希望有创建自己的实现的麻烦。有没有一种简单的方法来创建一个存根 RESTful Web 服务,该服务将返回一些静态数据,而无需编写完整的 WS 应用程序来执行此操作?

I want to create an android application, this application will make RESTful calls to a web service to obtain some data.

I know what the RESTful interface will be, but I don't want the hassle of creating my own implementation. Is there an easy way to create a stub RESTful web service that will return some static data without having to write a full blown WS application to do this?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

浸婚纱 2025-01-01 14:17:01

我发现如果您想测试实际的 HTTP 调用代码,使用 Sinatra 对于此类事情非常有用。您可以让端点在几秒钟内返回数据。需要很少的 Ruby 知识。

require 'sinatra'
require 'json'

get '/Person' do
    content_type :json
    { :id => 345, :key2 => 'John Doe' }.to_json
end

返回一个简单的 json 对象就足够了。

I've found using Sinatra really useful for this sort of thing if you want to test the actual HTTP calling code. You can have a endpoint returning data in seconds. Very little Ruby knowledge required.

require 'sinatra'
require 'json'

get '/Person' do
    content_type :json
    { :id => 345, :key2 => 'John Doe' }.to_json
end

Is all you would need to return a simple json object.

思慕 2025-01-01 14:17:01

其中一种方法(与 Vinnie 的方法类似)是在本地实现 Web 服务。例如,您的网络服务允许您登录用户并获取在线用户列表。

Webservice 接口如下所示:

public interface WebService {
    public LoginResponse login(String user, String pass) throws Exception;
    public UsersOnlineResponse getOnlineUsers() throws Exception;
}

然后,我们为将在生产中使用的远程 Webservice 实现此接口。远程实现在 HTTP 客户端的帮助下进行 HTTP 调用,检索响应并将其解析为适当的响应对象。以下是其中的一个片段:

public class RemoteWebService implements WebService {
    private AndroidHttpClient client = AndroidHttpClient.newInstance(USER_AGENT);

    @Override
    public LoginResponse login(String user, String pass) throws Exception {
        LoginResponse response = client.execute(
            createPostRequest(METHOD_LOGIN, user, pass), 
            new JsonResponseHandler(LoginResponse.class));

        handleResponse(response); // verify response, throw exceptions if needed
        return response;
    }
}

出于测试目的,当 webservice 不可用或正在开发时,我们实现本地 webservice。本地实现从资产文件夹中获取预定义的 JSON 响应,并将其解析为适当的响应对象。如何实现 Web 服务行为取决于您:它可以是简单的静态响应或一些随机/依赖于验证的响应。这是其中的一部分:

public class LocalWebService implements WebService {
    private Context context;

    public LocalWebService(Context context) {
        this.context = context;
    }

    @Override
    public LoginResponse login(String user, String pass) throws Exception {
        Thread.sleep(DELAY); //emulate network delay

        if (validateParams(user, pass)) {
            return parseAssetsJson("ws/login.json", LoginResponse.class);
        } else {
            Response response = parseAssetsJson("ws/status_bad_request.json", Response.class);
            throw new WebServiceException(response);
        }
    }

    public <T> T parseAssetsJson(String filename, Class<T> klass) throws IOException {
        InputStream is = context.getAssets().open(filename);
        return JsonParser.getInstance().fromJson(new InputStreamReader(is), klass);
    }
}

接下来,我们希望在实现之间轻松切换。这两种 Web 服务实现的使用都是透明的,因为我们使用 WebService 接口。因此,我们将在应用程序启动时配置 WebService 实例。 Application 类满足我们的需求:

public class App extends Application {
    public static final boolean USE_LOCAL_WS = false;
    private static WebService webService;

    public static getWebService() {
        return webService;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        webService = USE_LOCAL_WS ? new LocalWebService(this) : new RemoteWebService();
    }
}

One of the approaches (similar to Vinnie's) is to make a local implementation of your webservice. For example, your webservice allows you to log a user in and to get a list of users online.

The webservice interface looks like this:

public interface WebService {
    public LoginResponse login(String user, String pass) throws Exception;
    public UsersOnlineResponse getOnlineUsers() throws Exception;
}

Then, we implement this interface for remote webservice which will be used in production. Remote implementation makes HTTP calls with help of HTTP client, retrieves response and parses it to an appropriate response object. Here is a fragment of it:

public class RemoteWebService implements WebService {
    private AndroidHttpClient client = AndroidHttpClient.newInstance(USER_AGENT);

    @Override
    public LoginResponse login(String user, String pass) throws Exception {
        LoginResponse response = client.execute(
            createPostRequest(METHOD_LOGIN, user, pass), 
            new JsonResponseHandler(LoginResponse.class));

        handleResponse(response); // verify response, throw exceptions if needed
        return response;
    }
}

For testing purposes, when webservice is not available or is being developed, we implement local webservice. Local implementation takes predefined JSON responses from assets folder and parses it to an appropriate response object. It's up to you how to implement webservice behaviour: it can be simple static responses or some random/validation-dependent responses. Here is the part of it:

public class LocalWebService implements WebService {
    private Context context;

    public LocalWebService(Context context) {
        this.context = context;
    }

    @Override
    public LoginResponse login(String user, String pass) throws Exception {
        Thread.sleep(DELAY); //emulate network delay

        if (validateParams(user, pass)) {
            return parseAssetsJson("ws/login.json", LoginResponse.class);
        } else {
            Response response = parseAssetsJson("ws/status_bad_request.json", Response.class);
            throw new WebServiceException(response);
        }
    }

    public <T> T parseAssetsJson(String filename, Class<T> klass) throws IOException {
        InputStream is = context.getAssets().open(filename);
        return JsonParser.getInstance().fromJson(new InputStreamReader(is), klass);
    }
}

Next, we want to switch between implementations painlessly. The usage of both implementations of the webservice is transparent, because we use WebService interface. So, we'll configure the WebService instance on app launch. Application class suits our needs:

public class App extends Application {
    public static final boolean USE_LOCAL_WS = false;
    private static WebService webService;

    public static getWebService() {
        return webService;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        webService = USE_LOCAL_WS ? new LocalWebService(this) : new RemoteWebService();
    }
}
微凉 2025-01-01 14:17:01

我最终出于类似的目的编写了一个模拟服务工具: https://github.com/clafonta/Mockey/ wiki

模拟服务是快速构建 UI 和验证客户端代码的绝佳工具,但它可能会成为一个兔子洞,因此我建议您在构建自己的服务之前使用已经存在的东西。当你搜索“mock”时,Github 上有很多结果。无论您做什么,以下都是您可能会遇到的一些关键障碍。

  • 您最终会使用错误的数据/JSON 格式。 例如,您的应用程序在模拟服务中运行良好,但在访问真实服务时会中断,因为您的应用程序使用 JSON 对象,但真实服务返回一个 JSON 对象数组。为了避免这种情况,您可以尝试使用 JSON Schema 来帮助突出显示模拟服务中无效的 JSON 模型。

  • 您的应用未发出有效请求。您的模拟服务通常不会关心传入的请求。例如,真正的服务需要一个“customerID”,而您的应用程序永远不会将其传入。为避免这种情况,您可以在模拟服务中构建一些“必需的请求参数”验证逻辑。

  • 测试挑战。如果您想测试简单的“快乐路径”之外的东西,您的自动化功能测试方法需要与模拟服务工具进行交互。例如,您运行测试“用户 A 登录并看到 0 条消息”与“用户 B 登录并看到 20 条消息”。

I ended up writing a mock service tool for a similar purpose: https://github.com/clafonta/Mockey/wiki

A mock service is a great tool for quickly building UIs and validating your client code, but it can become a rabbit hole, so I recommend you use something that is already out there before building your own. Github has plenty of results when you search for 'mock'. Regardless of what you do, here are a few key stumbling blocks that you may encounter.

  • You end up working with the wrong data/JSON format. For example, your app works great with the mock service, but breaks when hitting the real service because your app consumes a JSON object but the real service returns an Array of JSON objects. To avoid this, you could try using JSON Schema to help highlight invalid JSON models in your mock service.

  • Your app doesn't make a valid request. Your mock service will typically not care about the incoming request. For example, the real service needs a "customerID" and your app never passes it in. To avoid this, you could build some "required request parameter" validation logic in your mock service.

  • Testing challenges. Your automated functional testing approach needs to interact with your mock service tool if you want to test things beyond the simple "happy path". For example, you run your test "user A logs-in and sees 0 messages" vs. "user B logs-in and sees 20 messages".

滴情不沾 2025-01-01 14:17:01

最好的办法可能是在开发应用程序代码时为 REST Web 服务创建一个模拟,然后在编写应用程序后将其替换为代码以调用返回“真实”数据的实际 Web 服务。

我目前正在编写一个与您的应用程序非常相似的应用程序,它(像您一样)从 RESTful Web 应用程序获取数据。在我的应用程序中,我遵循 GWT 推荐的 MVP 模式,并且Martin Fowler 也将其记录为 PassiveView 模式。

您想要做的是将 REST Web 服务调用的代码抽象为接口(模型)。该模型类的职责是向 Presenter/Controller 提供数据。 Presenter 将处理您的所有业务逻辑,然后将数据传递到视图(视图应该非常愚蠢,也允许它被模拟)。在测试期间,您将创建一个 MockModel 来实现模型接口并将测试数据传递给 Presenter - 根本不需要进行实际的 Web 服务调用!然后,当您准备好时,您将用实际的 Web 服务替换此类并开始集成测试。

这种方法还有一个额外的好处,那就是可以轻松地在模拟模型中创建特定的(且可重复的)测试用例。如果您无法控制实际的 Web 服务(我假设您没有),那么这可能很难(甚至不可能)实现。结果应该是一个更健壮、经过更好测试的应用程序,而无需创建任何测试 XML 或 JSON 或自行创建 Web 服务。

Probably the best thing to do is create a mock for the REST web service service while you're developing your application code and then replace it with code to call the actual web service returning "real" data, once your application is written.

I'm currently writing a very similar application to yours which (like you) obtains data from a RESTful web application. In my application, I'm following the MVP pattern recommended by GWT and is also documented by Martin Fowler as the PassiveView pattern.

What you want to do is abstract away the code to make the REST web service call into an interface (the Model). The responsibility of this model class is to provide data to the Presenter/Controller. The Presenter will handle all of your business logic and then pass data up to the view (the view should be pretty dumb as well allowing it to also be mocked out). During testing, you will create a MockModel to implement the model interface and pass test data to the Presenter - without making an actual web service call at all! Then, when you're ready, you will replace this class with the actual web service and start your integration testing.

This approach has the added benefit in that it will be easy to create specific (and repeatable) test cases in your mock model. If you don't have control of the actual web service (and I'm assuming you don't), this can be difficult (or even to impossible) to achieve. The result should be a more robust, better tested application without to need to create any test XML or JSON or creating the web services yourself.

小姐丶请自重 2025-01-01 14:17:01

创建一些带有虚拟响应的文件并将其放入文件夹中。现在转到命令行并执行以下命令:
python -m SimpleHTTPServer

您现在可以访问这些文件和虚拟响应
http://:8000

Create some files with dummy responses and put into a folder. Now go to command-line and execute the following:
python -m SimpleHTTPServer

You can now access these files and dummy responses at
http://:8000

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文