UPDATE
进一步思考应用程序架构,我不需要测试 Sails.js 控制器的请求/响应——在此应用程序的上下文中,控制器非常愚蠢,因为它们只是传递 JSON 对象。因此,我真正需要测试的是我的服务正在将外部 API 的对象转换为应用程序的内部 DTO,该内部 DTO 将用作 JSON 返回。换句话说,对我来说,测试实际的翻译比确保控制器通过它更重要,我们可以放心地假设情况总是如此。
话虽这么说,我将我的单元测试套件从 Jasmine 切换到 Chad 建议的 Mocha、Chai 和 Sinon 组合。在我看来,Mocha 中的异步钩子看起来更干净。我使用的一个添加库是Nock https://github.com/pgte/nock,一个旨在模拟 HTTP 请求的库,以便我可以拦截我的服务类对 API 的调用并返回一个存根对象。
因此,回顾一下,我放弃了对控制器进行单元测试,因为它对于我的用例来说是多余的。我需要测试的重要功能是将外部 API 的对象转换为我的内部应用程序的等效 DTO。
下面针对实际服务进行单元测试。请注意,这个特定的测试不需要 Sinon 进行存根/模拟,因为 Nock 为我处理了这个问题:
var Sails = require('sails');
var sinon = require('sinon'); // Mocking/stubbing/spying
var assert = require('chai').assert; // Assertions
var nock = require('nock'); // HTTP Request Mocking
var constants = require('../constants/externalSystemsConstants');
var Battlefield4Service = require('./battlefield4Service');
describe('External Services', function () {
// create a variable to hold the instantiated sails server
var app, battlefield4Service;
// Global before hook
before(function (done) {
// Lift Sails and start the server
Sails.lift({
log: {
level: 'error'
}
}, function (err, sails) {
app = sails;
done(err, sails);
});
});
// Global after hook
after(function (done) {
app.lower(done);
});
describe('Battlefield 4 Service', function () {
var userName, platform, kills, skill, deaths, killAssists, shotsHit, shotsFired;
before(function () {
// Mock data points
userName = 'dummyUser';
platform = 'ps3';
kills = 200;
skill = 300;
deaths = 220;
killAssists = 300;
shotsHit = 2346;
shotsFired = 7800;
var mockReturnJson = {
player: {
name: userName,
plat: platform
},
stats: {
kills: kills,
skill: skill,
deaths: deaths,
killAssists: killAssists,
shotsHit: shotsHit,
shotsFired: shotsFired
}
};
// Mock response from BF4 API
battlefield4Service = nock('http://' + constants.BF4_SERVICE_URI_HOST)
.get(constants.BF4_SERVICE_URI_PATH.replace('[platform]', platform).replace('[name]', userName))
.reply(200, mockReturnJson);
});
it('Should translate BF4 API data to FPSStatsDTO', function (done) {
var service = new Battlefield4Service();
service.getPlayerInfo(userName, platform, function (fpsStats) {
assert(fpsStats !== null);
assert(fpsStats !== undefined);
assert(fpsStats.kills === kills, 'kills');
assert(fpsStats.deaths === deaths, 'deaths');
assert(fpsStats.killAssists === killAssists, 'deaths')
assert(fpsStats.kdr === kills / deaths, 'kdr');
assert(fpsStats.shotsFired === shotsFired, 'shotsFired');
assert(fpsStats.shotsHit === shotsHit, 'shotsHit');
assert(fpsStats.shotsAccuracy === shotsHit / shotsFired, 'shotsAccuracy');
assert(fpsStats.userName === userName, 'userName');
assert(fpsStats.platform === platform, 'platform');
done();
});
});
});
});