【发布时间】:2016-12-27 03:18:59
【问题描述】:
我正在向我公司的应用程序引入 javascript 单元测试。我主要使用 AngularJS,但他们选择的框架是 Knockout。代码在设计上是相对模块化的(感谢 Knockout),所以我认为围绕代码添加单元测试会很容易(很像 Angular)。
但是,还有更复杂的情况:系统使用require.js 作为 IoC 容器。此外,我的测试运行程序是 Chutzpah,它是无头的/在 Visual Studio 测试资源管理器中。我曾尝试使用 SquireJS 模拟依赖项,但在尝试实例化 ViewModel 时遇到了障碍:它需要在组件中设置并继承的某些依赖项。我尝试加载具有进一步依赖关系的组件,依此类推。下面我有一个概述了这一点的设置的简化版本。实例化此视图模型的最佳方法是什么,以便我可以使用 Squire 模拟依赖项并运行我的测试?
组件
define(function (require) {
var Boiler = require('Boiler'),
BaseViewModel = require('../../../../core/baseClasses/BaseViewModel'),
viewTemplate = require('text!./view.html'),
viewModel = require('./viewModel'),
nls = require('i18n!./nls/resources');
var Component = function (initializingParameters) {
//...blah blah blah setup things
};
return Component;
});
视图模型
define(function (require) {
var Constants = require('../../../../core/constants');
var momDate = moment().format('MMM DD, YYYY');
var Utils = require("../../../../model/utils");
var utils = new Utils();
var otherComponentUtils = require("../../../otherModule/otherComponent/OtherComponentUtils");
var otherComponentUtils = new OtherComponentUtils();
var ViewModel = function (globalContext, moduleContext, dataContext, domElement) {
var Self = this;
Self.super(moduleContext, dataContext, resPickerContext);
var constants = new Constants();
var utils = require("../../../../model/utils");
var Utils = new utils();
Self.Items = ko.observableArray().extend({ throttle: 500 });
//a bunch more Knockout object setup
Self.GetAuthorizationTypesArray = function (itemId) {
dataContext.dataRequestHandler(dataContext.serviceConstants.GetTransactionTypes, { ItemId: itemId },
function (data) {
if (data != null && data.length !== 0) {
Self.TransactionTypeArray(data);
var transactionTypeArray = Self.TransactionTypeArray();
if (transactionTypeArray.length) {
var paymentInfo = Self.PaymentInfo();
if (paymentInfo !== null && paymentInfo !== undefined && paymentInfo.IsSpecial) {
var childThing = Self.ChildThing();
dataContext.dataRequestHandler(dataContext.serviceConstants.GetChild, { ChildId: childThing.ChildId, SpecialId: childThing.SpecialID }, function (data) {
var child = data[0];
var specialTypeId = child.ListId;
if (specialTypeId === 13)
Self.BigThing.Type(1);
else
Self.BigThing.Type(2);
}, Self.ShowError);
}
}
}
},
Self.ShowError);
}
return ViewModel;
});
chutzpah.json
{
"Framework": "jasmine",
"TestHarnessReferenceMode": "AMD",
"TestHarnessLocationMode": "SettingsFileAdjacent",
"RootReferencePathMode": "SettingsFileDirectory",
"References": [
{ "Path": "../../myWebApp/Scripts/libs/assets/plugins/jquery-1.10.2.min.js" },
{ "Path": "../../myWebApp/scripts/libs/moment/moment.min.js" },
{ "Path": "../../myWebApp/Scripts/libs/require/require.js" },
{ "Path": "unittest.main.js" }
],
"Tests": [
{
"Path": "app",
"Includes": [ "*.tests.js" ]
}
]
}
unittest.main.js
"use strict";
require.config({
paths: {
'jasmine': ['jasmine/jasmine'],
'jasmine-html': ['jasmine/jasmine-html'],
'jasmine-boot': ['jasmine/boot'],
squire: 'Squire'
},
shim: {
'jasmine-html': {
deps : ['jasmine']
},
'jasmine-boot': {
deps : ['jasmine', 'jasmine-html']
},
'squire': {
exports: 'squire'
}
},
config: {
text: {
useXhr: function (url, protocol, hostname, port) { return true },
//Valid values are 'node', 'xhr', or 'rhino'
env: 'xhr'
}
},
waitSeconds: 0
});
viewModel.tests.js
define(function (require) {
var testTargetPath = '../../myWebApp/Scripts/app/modules/thisModule/myViewModel';
describe('My View Model', function () {
var mockDataContext;
var mockResponseData;
var injector;
var viewModel;
beforeEach(function () {
var Squire = require('Squire');
injector = new Squire();
});
beforeEach(function () {
mockResponseData = {};
mockDataContext = {
dataRequestHandler: function (url, data, onSuccess) {
onSuccess(mockResponseData[url]);
},
serviceConstants: {
GetTransactionTypes: 'getTransactionTypes',
GetChild: 'getNewPolicy'
}
};
injector.mock("dataContext", mockDataContext);
});
beforeEach(function (done) {
injector.require([testTargetPath], function (ViewModel) {
viewModel = new ViewModel();
done();
});
});
it('gets authorization type array', function () {
spyOn(mockDataContext, 'dataRequestHandler').and.callThrough();
mockResponseData = {
'getTransactionTypes': [
{ name: 'auth type 1', TransactionTypeId: 90210 },
{ name: 'auth type 2', TransactionTypeId: 42 },
]
};
viewModel.GetAuthorizationTypesArray(9266);
expect(mockDataContext.dataRequestHandler).toHaveBeenCalledWith('getTransactionTypes', { ItemId: 9266 });
expect(viewModel.TransactionTypeArray()).toBe(mockResponseData);
});
});
});
具体来说,在ViewModel 中,当测试运行时,它会抱怨super 未定义。
【问题讨论】:
标签: unit-testing knockout.js requirejs jasmine chutzpah