【问题标题】:Using Grunt to Mock Endpoints使用 Grunt 模拟端点
【发布时间】:2013-07-29 21:33:31
【问题描述】:

我正在使用 Yeoman、Grunt 和 Bower 构建一个平台,用于构建独立于后端的前端。我的想法是我的所有(AngularJS)控制器、服务、工厂等都存在于这个项目中,然后根据 grunt 构建的结果注入到我的服务器端代码库中。

我的问题是:

如何模拟端点,以便 Grunt 服务器响应与我的 (Rails) 应用程序相同的端点?

目前我正在使用:

 angular.module('myApp', ['ngResource'])

 .run(['$rootScope', function ($rootScope) {
     $rootScope.testState = 'test';
  }]);

然后在我的每个单独的服务中:

   mockJSON = {'foo': 'myMockJSON'}

在每种方法上:

   if($rootScope.testState == 'test'){
    return mockJSON;
  }
  else {
    real service logic with $q/$http goes here
  }

然后在grunt build 之后,testState = 'test' 被删除。

这显然是一个相对笨拙的架构。我怎样才能避免它?如何让 Grunt 响应与我的应用程序相同的端点(其中一些具有动态参数)应用一些逻辑(如果需要),并提供一个 json 文件(可能依赖于路径参数)?

【问题讨论】:

    标签: rest angularjs mocking gruntjs yeoman


    【解决方案1】:

    我已通过使用 express 编写一个以静态 json 响应的服务器来解决此问题。

    首先,我在我的项目中创建了一个名为“api”的目录。在该目录中,我有以下文件:

    package.json:

       {
         "name": "mockAPI",
         "version": "0.0.0",
         "dependencies": {
            "express": "~3.3.4"
          }
       }
    

    然后我在这个目录中运行npm install

    index.js:

        module.exports = require('./lib/server');
    

    lib/server.js:

        express = require('express');
        var app = express();
    
        app.get('/my/endpoint', function(req, res){
            res.json({'foo': 'myMockJSON'});
       });
    
        module.exports = app
    

    最后在我的全球Gruntfile.js:

             connect: {
                options: {
                   port: 9000,
                   hostname: 'localhost',
                },
                livereload: {
                  options: {
                     middleware: function (connect, options) {
                       return [
                         lrSnippet,
                         mountFolder(connect, '.tmp'),
                         mountFolder(connect, yeomanConfig.app),
                         require('./api')
                       ];
                   }
                }
             },
    

    然后服务发出请求,快递服务器提供正确的 JSON。

    grunt build 之后,express 服务器被简单地替换为 rails 服务器。

    【讨论】:

    • 这很好用,但是如何在不重新启动服务器的情况下重新加载 lib/server.js 中的更改?
    • 这不是我最终解决的问题,因为对 lib/server 的更改很少见(它是一家小公司),如果您想出一个解决方案,我绝对希望听到您的解决方案
    • @pablomolnar 我编写的插件(答案如下)允许您在开发服务器仍在运行时修改模拟响应。 stackoverflow.com/a/25714447/895309
    • 看看swagger-api-mockrest-json 一起使用效果很好。
    【解决方案2】:

    grunt-contrib-connect v.0.7.0 开始,您还可以将自定义中间件添加到现有中间件堆栈中,而无需手动重建现有中间件堆栈。

    livereload: {
        options: {
            open: true,
            base: [
                '.tmp',
                '<%= config.app %>'
            ],
            middleware: function(connect, options, middlewares) {
                // inject a custom middleware into the array of default middlewares
                middlewares.push(function(req, res, next) {
                    if (req.url !== '/my/endpoint') {
                        return next();
                    }
                    res.writeHead(200, {'Content-Type': 'application/json' });
                    res.end("{'foo': 'myMockJSON'}");
                });
                return middlewares;
            }
        }
    },
    

    官方文档见https://github.com/gruntjs/grunt-contrib-connect#middleware

    【讨论】:

      【解决方案3】:

      或者,您可以使用 grunt-connect-proxy 将测试服务器中缺少的所有内容代理到实际后端。

      它很容易安装,在将代理添加到 livereload 连接中间件时要记住的一件事是最后添加它,如下所示:

      middleware: function (connect) {
          return [
              lrSnippet,
              mountFolder(connect, '.tmp'),
              mountFolder(connect, yeomanConfig.app),
              proxySnippet
          ];
      }
      

      【讨论】:

        【解决方案4】:

        grunt-connect-prism 类似于 Ruby 项目VCR。它为前端开发人员提供了一种简单的方法来记录他们的 API(或其他远程源)返回的 HTTP 响应并在以后重放它们。它基本上是一个 HTTP 缓存,但适用于开发单页应用程序 (SPA) 的开发人员。 You can also generate stubs for API calls that don't exist, and populate them the way you want.

        它对于在开发过程中模拟复杂和高延迟的 API 调用很有用。在仅为您的 SPA 编写 e2e 测试时,它也很有用,从等式中删除服务器。这样可以更快地执行您的 e2e 测试套件。

        Prism 通过将自定义连接中间件添加到grunt-contrib-connect 插件提供的连接服务器来工作。在“记录”模式下,它会在文件系统上为每个响应生成一个文件,内容如下:

          {
            "requestUrl": "/api/ponies",
            "contentType": "application/json",
            "statusCode": 200,
            "data": {
              "text": "my little ponies"
            }
          }
        

        免责声明:我是这个项目的作者。

        【讨论】:

          【解决方案5】:

          您可以使用 Apache 代理并使用 gruntjs 连接您的 REST 服务器。

          Apache 会这样做: 代理/-> gruntjs 代理/服务 -> REST 服务器


          您会使用您的应用程序访问 Apache,而 angular.js 应用程序会认为它正在与自己对话,因此不会出现跨域问题。

          这里有一个关于如何设置的很棒的教程: http://alfrescoblog.com/2014/06/14/angular-js-activiti-webapp-with-activiti-rest/

          【讨论】:

            【解决方案6】:

            只是我基于亚伯拉罕 P 的回答的替代方式。它不需要在“api”文件夹中安装 express。我可以为某些文件分离模拟服务。例如,我的 'api' 文件夹包含 3 个文件:

            API\

            • index.js // 分配所有“模块”,然后简单地要求它。
            • user.js // 全部为用户模拟
            • product.js // 全部模拟产品

            文件user.js

            var user = function(req, res, next) {
            if (req.method === 'POST' && req.url.indexOf('/user') === 0) {
                 res.end(
                      JSON.stringify({
                                'id' : '5463c277-87c4-4f1d-8f95-7d895304de12',
                                'role' : 'admin'
                        })
                     );
                }
                else {
                    next();
                }
            }
            module.exports = user;
            

            文件product.js

            var product = function(req, res, next) {
            if (req.method === 'POST' && req.url.indexOf('/product') === 0) {
                 res.end(
                      JSON.stringify({
                                'id' : '5463c277-87c4-4f1d-8f95-7d895304de12',
                                'name' : 'test',
                                'category': 'test'
                        })
                     );
                }
                else {
                    next();
                }
            }
            module.exports = product;
            

            index.js 只是分配所有的“模块”,我们只是要求它。

            module.exports = {
                product: require('./product.js'),
                user: require('./user.js')
            };
            

            我的 Gruntfile.js 文件

             connect: {
                  options: {
                    port: 9000,
                    // Change this to '0.0.0.0' to access the server from outside.
                    hostname: 'localhost',
                    livereload: 35729
                  },
                  livereload: {
                    options: {
                      open: true,
                      middleware: function (connect) {
            
                        return [
                          connect.static('.tmp'),
                          connect().use(
                            '/bower_components',
                            connect.static('./bower_components')
                          ),
                          connect.static(appConfig.app),
                          require('./api').user,
                          require('./api').product,
                        ];
                      }
                    }
                  }
            

            【讨论】:

              猜你喜欢
              • 2017-11-10
              • 2015-01-30
              • 2017-04-13
              • 1970-01-01
              • 1970-01-01
              • 2021-07-27
              • 1970-01-01
              • 2019-05-23
              • 2021-11-16
              相关资源
              最近更新 更多