完全集成测试NodeJS和客户端与Yeoman和Mocha [英] Full Integration Testing for NodeJS and the Client Side with Yeoman and Mocha

查看:105
本文介绍了完全集成测试NodeJS和客户端与Yeoman和Mocha的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有很棒的客户端测试,我和Yeoman一起运行。 Yeoman编译我的CoffeeScript,在服务器中打开测试页面,使用PhantomJS访问它,并将所有测试结果传递到命令行。这个过程非常简单,测试结果通过 alert()消息传递到Phantom进程,该进程创建一个临时文件并以JSON格式填充消息。

I got awesome client side tests that I run with Yeoman. Yeoman compiles my CoffeeScript, opens up the test page in a server, visit it with PhantomJS and pass all the tests results to the command line. The process is pretty hacky, the test results are passed via alert() messages to the Phantom process which creates a temporary file and fills it with the messages as JSON. Yeoman (well, Grunt) loops over the temporary file, parses the tests and displays them in the command line.

我解释这个过程的原因是我想添加一个一些东西给它。我也得到服务器端测试。它们使用mocha和supertest来检查API端点和Redis客户端,以确保数据库状态符合预期。但我想合并这两个测试套件!

The reason I explained the process is that I want to add a few things to it. I got server side tests as well. They use mocha and supertest to check the API endpoints and a Redis client to make sure the database state is as expected. But I want to merge those two test suites!

我不想为服务器调用编写客户端模拟响应。我不想发送服务器模拟数据。在某个地方,我将更改服务器或客户端,测试不会失败。我想做一个真正的集成测试。所以,每当一个测试完成在客户端我想要一个钩子在服务器端运行一个相关的测试(检查db状态,会话状态,移动到不同的测试页)。

I don't want to write client side mock response for the server calls. I don't want to send the server mock data. Somewhere along the way I'll change the server or the client and the test will not fail. I want to do a real integration testing. So, whenever a test finishes in the client side I want a hook to run a relevant test on the server side (checking db state, session state, moving to a different test page).

有没有任何解决方案?

Are there any solutions to this? Or, altenatively, where do I start hacking on Yeoman / Grunt / grunt-mocha to make this work?

我认为在grunt-mocha中的Phantom Handlers是一个很好的地方开始:

I think the Phantom Handlers in grunt-mocha is a good place to start:

// Handle methods passed from PhantomJS, including Mocha hooks.
  var phantomHandlers = {
    // Mocha hooks.
    suiteStart: function(name) {
      unfinished[name] = true;
      currentModule = name;
    },
    suiteDone: function(name, failed, passed, total) {
      delete unfinished[name];
    },
    testStart: function(name) {
      currentTest = (currentModule ? currentModule + ' - ' : '') + name;
      verbose.write(currentTest + '...');
    },
    testFail: function(name, result) {
        result.testName = currentTest;
        failedAssertions.push(result);
    },
    testDone: function(title, state) {
      // Log errors if necessary, otherwise success.
      if (state == 'failed') {
        // list assertions
        if (option('verbose')) {
          log.error();
          logFailedAssertions();
        } else {
          log.write('F'.red);
        }
      } else {
        verbose.ok().or.write('.');
      }
    },
    done: function(failed, passed, total, duration) {
      var nDuration = parseFloat(duration) || 0;
      status.failed += failed;
      status.passed += passed;
      status.total += total;
      status.duration += Math.round(nDuration*100)/100;
      // Print assertion errors here, if verbose mode is disabled.
      if (!option('verbose')) {
        if (failed > 0) {
          log.writeln();
          logFailedAssertions();
        } else {
          log.ok();
        }
      }
    },
    // Error handlers.
    done_fail: function(url) {
      verbose.write('Running PhantomJS...').or.write('...');
      log.error();
      grunt.warn('PhantomJS unable to load "' + url + '" URI.', 90);
    },
    done_timeout: function() {
      log.writeln();
      grunt.warn('PhantomJS timed out, possibly due to a missing Mocha run() call.', 90);
    },

    // console.log pass-through.
    // console: console.log.bind(console),
    // Debugging messages.
    debug: log.debug.bind(log, 'phantomjs')
  };

谢谢!

推荐答案

我不知道 Yeoman - 我还没有尝试过 - 但我得到了剩下的难题运行。

I don't know about Yeoman - I haven't tried it yet - but I got the rest of the puzzle running. I believe you will figure out the rest.

问题,你谈论的情况,当你有客户端测试和服务器端测试运行与模拟。我假设,由于某些原因,你不能得到两个测试集运行相同的模拟。否则,如果您更改了客户端上的mock,服务器端测试将失败,因为它们会获取损坏的模拟数据。

In your question you were talking about the situation when you have both client-side tests and server-side tests running with mocks. I assume that for some reason you can't get both test sets running with the same mocks. Otherwise, if you changed the mocks on client-side your server-side tests would fail because they would get the broken mock data.

您需要的是集成测试当您在无网络浏览器中运行一些客户端代码时,服务器端代码也会运行。此外,只是运行你的服务器端和客户端代码是不够的,你也想要能够在双方都提出断言,不是吗?

What you need are the integration tests so when you run some client-side code in your headless browser your server-side code would also run. Moreover, simply running your server-side and client-side code is not enough, you also want to be able to put assertions on both sides, don't you?

我在网上找到的大部分集成测试示例都使用 Selenium Zombie.js 。前者是一个基于Java的大型框架,用于驱动真正的浏览器,而后者则是 jsdom 的简单包装器。我假设您对使用其中的任何一个犹豫不决,并且希望 PhantomJS 。当然,棘手的部分是从Node应用程序运行。

Most of the examples of integration tests that I found online either use Selenium or Zombie.js. The former is a big Java-based framework to drive real browsers while the later is a simple wrapper around jsdom. I assume you're hesitant to use either of those and would prefer PhantomJS. The tricky part, of course, is to get that running from your Node app. And I got just that.

有两个节点模块来驱动PhantomJS:

There are two node modules to drive PhantomJS:


  1. 幻影

  2. node-phantom

  1. phantom
  2. node-phantom

不幸的是,这两个项目似乎都被作者和其他社区成员抛弃了fork他们并适应他们的需要。这意味着这两个项目都被分叉了很多次,所有的叉子刚刚运行。 API几乎不存在。我使用幽灵叉子之一运行测试(谢谢你, Seb Vincent )。这里有一个简单的应用程序:

Unfortunately, both projects seem abandoned by their authors and other community members fork them and adapt to their needs. That means that both projects got forked numerous times and all forks are barely running. The API is almost non-existent. I got my tests running with one of the phantom forks (Thank you, Seb Vincent). Here's a simple app:

'use strict';
var express = require('express');

var app = express();

app.APP = {}; // we'll use it to check the state of the server in our tests

app.configure(function () {
    app.use(express.static(__dirname + '/public'));
});

app.get('/user/:name', function (req, res) {
    var data = app.APP.data = {
        name: req.params.name,
        secret: req.query.secret
    };
    res.send(data);
});

module.exports = app;

    app.listen(3000);
})();

它侦听 / user 的请求返回路径参数 name 和查询参数 secret 。这是我调用服务器的页面:

It listens for request to /user and returns path parameter name and query parameter secret. Here's the page where I call the server:

window.APP = {};

(function () {
    'use strict';

    var name = 'Alex', secret ='Secret';
    var xhr = new XMLHttpRequest();
    xhr.open('get', '/user/' + name + '?secret=' + secret);
    xhr.onload = function (e) {
        APP.result = JSON.parse(xhr.responseText);
    };
    xhr.send();
})();

这里是一个简单的测试:

And here's a simple test:

describe('Simple user lookup', function () {
    'use strict';

    var browser, server;

    before(function (done) {
        // get our browser and server up and running
        phantom.create(function (ph) {
            ph.createPage(function (tab) {
                browser = tab;
                server = require('../app');
                server.listen(3000, function () {
                    done();
                });
            });
        });
    });

    it('should return data back', function (done) {
        browser.open('http://localhost:3000/app.html', function (status) {

            setTimeout(function () {
                browser.evaluate(function inBrowser() {
                    // this will be executed on a client-side
                    return window.APP.result;
                }, function fromBrowser(result) {
                    // server-side asserts
                    expect(server.APP.data.name).to.equal('Alex');
                    expect(server.APP.data.secret).to.equal('Secret');
                    // client-side asserts
                    expect(result.name).to.equal('Alex');
                    expect(result.secret).to.equal('Secret');
                    done();
                });
            }, 1000); // give time for xhr to run

        });
    });
});

正如你所看到的,我必须在超时时间内轮询服务器。这是因为所有的幻影绑定是不完整的,太限制。正如您所见,我可以在一次测试中检查客户端状态和服务器状态。

As you can see I have to poll the server inside the timeout. That's because all the phantom bindings are incomplete and too limiting. As you can see I'm able to check both client state and server state in a single test.

使用 Mocha mocha -t 2s 您可能需要增加默认超时设置,以便运行更多演进的测试。

Run your tests with Mocha: mocha -t 2s You'll probably need to increase the default timeout setting for more evolved tests to run.

所以,你可以看到整个事情是可行的。 下面是完整示例的回购。

这篇关于完全集成测试NodeJS和客户端与Yeoman和Mocha的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆