Javascript 如何在单元测试之间重置requirejs模块
我有一个JavaScript项目,我想观察TDD方法。为此,我选择了karma框架和requirejs库,并遵循karma文档中演示的示例 有一个单元测试文件的示例,它是:Javascript 如何在单元测试之间重置requirejs模块,javascript,unit-testing,requirejs,karma-runner,Javascript,Unit Testing,Requirejs,Karma Runner,我有一个JavaScript项目,我想观察TDD方法。为此,我选择了karma框架和requirejs库,并遵循karma文档中演示的示例 有一个单元测试文件的示例,它是: define(['app', 'jquery', 'underscore'], function(App, $, _) { describe('just checking', function() { it('works for app', function() { var
define(['app', 'jquery', 'underscore'], function(App, $, _) {
describe('just checking', function() {
it('works for app', function() {
var el = $('<div></div>');
var app = new App(el);
app.render();
expect(el.text()).toEqual('require.js up and running');
});
it('works for underscore', function() {
// just checking that _ works
expect(_.size([1,2,3])).toEqual(3);
});
});
});
define(['app','jquery','下划线'],函数(app,$,\ux){
描述('只是检查',函数(){
它('适用于应用程序',函数(){
变量el=$('');
var应用=新应用(el);
app.render();
expect(el.text()).toEqual('require.js启动并运行');
});
它('用于下划线',函数(){
//只是检查一下是否有效
期望(u.size([1,2,3])).toEqual(3);
});
});
});
这种方法的主要问题是无法为每个测试清除应用程序模块。因此,如果在一个it
调用中应用程序中有一些更改(如关闭变量更改等),那么它们可能会影响其他it
调用
有人能提出一些建议吗?这些是如此流行的工具,我不敢相信没有人遇到过这样的情况
因此,为了重述这个问题,我想问一下这些更具体的问题的答案:
- 有没有办法在requirejs中“重置”(清除)模块?(事实上,我想除了再次重新加载所有模块之外,没有其他方法了。)
- 有没有更好的方法来运行karma和requirejs,这样模块就不会有其他测试(
function calls)的任何残余(副作用)it
- 有没有办法在requirejs中“重置”(清除)模块
- 有没有更好的方法来运行karma和requirejs,这样模块就不会受到其他测试(it函数调用)的任何影响(副作用)
更好的方法是设计应用程序,使状态绑定到实例化的对象,而不是模块本身。这就是我在测试套件中为我的一个大型应用程序所做的。beforeach钩子重置需要重置的内容,并为每个测试重新实例化应用程序。在谷歌的帮助下,我找到了一个解决方案。我不能说它是理想的,但它至少可以工作,并且在每个测试中,所需的模块都处于原始状态 首先,需要有这样的
main.js
测试文件,它与中几乎相同,只是测试没有定义为模块,也没有包含为依赖项:
require.config({file
baseUrl: '/base',
paths: {},
shim: {},
deps: [],
callback: window.__karma__.start
});
在主业力形态中,这必须存在(你需要调整自己的路径)
在测试本身中,我们利用jasmine async测试功能和requirejs.unde方法“清除”模块(这将重置加载程序的内部状态,以忘记模块的先前定义,如中所述)
此方法有一个含义,即它不会重置其他模块,这些模块已经加载并依赖于重置模块,但如果一个人以正确的方式编写测试,也就是说他只测试一个模块(可能是一些父模块,子模块从中继承了一些行为),则这不应该是一个问题,因此,一次定义多个模块应该不难
describe('Some/Module tests', function() {
'use strict'
var M
beforeEach(function(done) {
requirejs.undef('src/Some/GParentModule')
requirejs.undef('src/Some/ParentModule')
requirejs.undef('src/Some/Module')
require(['src/Some/Module'], function(m) {
M = m
done()
})
})
it('some description', function() {
var i = 0
for (var prop in M) {
i++
}
expect(i).toEqual(1)
expect(prop).toEqual('init')
expect(M.init).toEqual(jasmine.any(Function))
})
})
我已经检查过了,在it
调用之间,对模块的更改不会持久,所以我认为,使用这种方法是安全的
谢谢大家的帮助,如果有人有更好的方法,请在这里回答。谢谢,但我不能同意您的建议,即设计应用程序,使状态绑定到您实例化的对象,而不是模块本身,因为即使我这样做(尽管我不想这样做),问题仍然存在,至少在JavaScript中是这样。由于模块定义是一个函数这一事实,即使我实例化了一个对象,我也不能在每次测试中都清楚地依赖它(至少可以更改一些闭包变量)。看来我已经找到了一个可接受的解决方案,我将把它作为一个答案发布below@user907860您一定对JavaScript的工作原理有一些误解,因为它是完全可行的。正如我在回答中所说,我已经做到了。你能提供一些代码示例吗?我的意思是,如果您在许多
it
调用中测试的模块只有一个require/define调用,那么您无法确定(只有在您没有侵入模块内部的情况下)它的状态是否已重置。因为,如果我在模块实例上调用一个方法,它是这样的:define(function(){var foo;return function(){this.method=function(){foo++}}})
。然后,如果我调用var-ins=new模块;ins.method()
在一个测试中,我将在另一个测试中使用foo+=1
这个模块。即使在另一个测试中(或在beforeach中),我调用var ins_2=new module
我仍将使用其内部foo变量递增1的模块
describe('Some/Module tests', function() {
'use strict'
var M
beforeEach(function(done) {
requirejs.undef('src/Some/GParentModule')
requirejs.undef('src/Some/ParentModule')
requirejs.undef('src/Some/Module')
require(['src/Some/Module'], function(m) {
M = m
done()
})
})
it('some description', function() {
var i = 0
for (var prop in M) {
i++
}
expect(i).toEqual(1)
expect(prop).toEqual('init')
expect(M.init).toEqual(jasmine.any(Function))
})
})