javascript 使用 Yeoman 和 Mocha 对 NodeJS 和客户端进行全面集成测试
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/13689110/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Full Integration Testing for NodeJS and the Client Side with Yeoman and Mocha
提问by CamelCamelCamel
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.
我使用 Yeoman 进行了很棒的客户端测试。Yeoman 编译我的 CoffeeScript,在服务器中打开测试页面,使用 PhantomJS 访问它并将所有测试结果传递到命令行。这个过程非常复杂,测试结果通过alert()
消息传递到 Phantom 进程,它创建一个临时文件并用 JSON 格式的消息填充它。Yeoman(好吧,Grunt)遍历临时文件,解析测试并将它们显示在命令行中。
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!
我解释这个过程的原因是我想添加一些东西。我也得到了服务器端测试。他们使用 mocha 和 supertest 检查 API 端点和 Redis 客户端以确保数据库状态符合预期。但我想合并这两个测试套件!
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?
有什么解决办法吗?或者,或者,我从哪里开始对 Yeoman / Grunt / grunt-mocha 进行黑客攻击以使其工作?
I think the Phantom Handlers in grunt-mocha is a good place to start:
我认为 grunt-mocha 中的 Phantom Handlers 是一个很好的起点:
// 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')
};
Thanks! There will be a bounty on this.
谢谢!对此会有赏金。
采纳答案by Andrew Андрей Листочкин
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.
我不知道Yeoman- 我还没有尝试过 - 但我已经完成了剩下的谜题。我相信你会弄清楚剩下的。
Why Doing Integration Tests?
为什么要做集成测试?
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?
您需要的是集成测试,因此当您在无头浏览器中运行一些客户端代码时,您的服务器端代码也会运行。而且,仅仅运行您的服务器端和客户端代码是不够的,您还希望能够在双方都放置断言,不是吗?
Integration Tests with Node and PhantomJS
Node 和 PhantomJS 的集成测试
Most of the examples of integration tests that I found online either use Seleniumor 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.
我在网上找到的大多数集成测试示例都使用Selenium或Zombie.js。前者是一个基于 Java 的大型框架,用于驱动真正的浏览器,而后者是一个简单的jsdom包装器。我假设您对使用其中任何一个犹豫不决,并且更喜欢PhantomJS。当然,棘手的部分是让它从你的 Node 应用程序中运行。而我就是这样。
There are two node modules to drive PhantomJS:
有两个节点模块来驱动 PhantomJS:
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:
不幸的是,这两个项目似乎都被他们的作者和其他社区成员分叉并适应他们的需求。这意味着这两个项目都被多次分叉,并且所有分叉都几乎没有运行。API 几乎不存在。我用其中一个幻影叉运行了我的测试(谢谢,Seb Vincent)。这是一个简单的应用程序:
'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);
})();
It listens for request to /user
and returns path parameter name
and query parameter secret
. Here's the page where I call the server:
它侦听请求/user
并返回路径参数name
和查询参数secret
。这是我调用服务器的页面:
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.
如您所见,我必须在超时内轮询服务器。那是因为所有幻象绑定都不完整且限制太多。如您所见,我可以在一次测试中同时检查客户端状态和服务器状态。
Run your tests with Mocha: mocha -t 2s
You'll probably need to increase the default timeout setting for more evolved tests to run.
使用Mocha运行您的测试:mocha -t 2s
您可能需要增加默认超时设置才能运行更高级的测试。
So, as you can see the whole thing is doable.Here's the repo with complete example.
所以,正如你所看到的,整个事情都是可行的。这是带有完整示例的回购。