最近,我转向使用依赖注入来帮助理解分离代码的简单途径,并有助测试。然而,Node.js中的模块依赖Node提供的系统API,这很难判断私有依赖被恰当的使用。一般的依赖注入很难在这种情况下使用,但现在不要放弃希望。
requireCauses
问题
Node.js很容易依照需求导入依赖。它运行的很好,并且比AMD模式加载器例如RequireJS要简单。当我们模拟那些依赖的时候问题就来了。如果Node.js中模型的加载是受控的,我们怎么做才能控制让伪对象在测试期间被使用到?我们可以使用Node的vm模式,通过vm我们可以再新的上下文中加载模型。运行在新的上下文中,我们可以控制需求反射出模型的方法。
解决方案
谢谢这篇文章,
现在可以给你提供一个相当不错的解决方案.
代码在下面:
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
var
vm
=
require('vm')
var
fs
=
require('fs')
var
path
=
require('path')
/**
*
Helper
for
unit
testing:
*
load
module
with
mocked
dependencies
*
allow
accessing
private
state
of
the
module
*
*
@param
{string}
filePath
Absolute
path
to
module
(file
to
load)
*
@param
{Object=}
mocks
Hash
of
mocked
dependencies
*/
exports.loadModule
=
function(filePath,
mocks)
{
mocks
=
mocks
||
{}
//
this
is
necessary
to
allow
relative
path
modules
within
loaded
file
//
i.e.
requiring
./some
inside
file
/a/b.js
needs
to
be
resolved
to
/a/some
var
resolveModule
=
function(module)
{
if
(module.charAt(0)
!==
'.')
return
module
return
path.resolve(path.dirname(filePath),
module)
}
var
exports
=
{}
var
context
=
{
require:
function(name)
{
return
mocks[name]
||
require(resolveModule(name))
},
console:
console,
exports:
exports,
module:
{
exports:
exports
}
}
vm.runInNewContext(fs.readFileSync(filePath),
context)
return
context
}
你也可以在
这里
下载代码片段
.
虽然在不是在文章发布最多的代码,
他仍然可以使用一些解释.
当我们测试时,
我们要加载这个模块进入测试,
使用theloadModulefunction代替ofrequire加载模块测试.
第一个参数filePath指定了我们要测试模型的查找位置。第二个参数mocks包含一个对象,对象的属性名称要和我们尝试require的模型的名称相匹配。那些属性指定的值就是伪对象,用来代替一般被require的模型。
本质上看就是用vm来加载和运行模型在另一个上下文中。换句话说,我们重建了全局变量(例如require和exports)以便我们能控制它们。需要注意的是我们编写了一个可用的新require函数。所做一切就是检查一下用执行的名字是否有一个模拟的依赖,如果每日有,我就就把它委托给那个常用的require函数。
使用模块加载器的例子
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
var
fs
=
require('fs')
module.exports
=
{
//
Do
something
with
`fs`
}
想象一下这个很酷,对吗?不管怎样,现在我们测试那个模块,但是我们要模拟fs来看看它是怎么在内部使用的。
//
Jasmine's
syntax
http://pivotal.github.com/jasmine/
describe('someModule',
function()
{
var
loadModule
=
require('module-loader').loadModule
var
module,
fsMock
beforeEach(function()
{
fsMock
=
{
//
a
mock
for
`fs`
}
//
load
the
module
with
mock
fs
instead
of
real
fs
module
=
loadModule('./web-server.js',
{fs:
fsMock})
})
it('should
work',
function()
{
//
a
test
that
utilizes
the
fact
that
we
can
now
control
`fs`
})
})
AngularJS 在实际应用中优点:
模板功能强大丰富,并且是声明式的,自带了丰富的Angular指令;
是一个比较完善的前端MV*框架,包含模板,数据双向绑定,路由,模块化,服务,过滤器,依赖注入等所有功能;
自定义Directive,比jQuery插件还灵活,但是需要深入了解Directive的一些特性,简单的封装容易,复杂一点官方没有提供详细的介绍文档,可以通过阅读源代码来找到某些我们需要的东西;
ng模块化比较大胆的引入了Java的一些东西(依赖注入),能够很容易的写出可复用的代码,对于敏捷开发的团队来说非常有帮助,即使UI变化很大,而且产品更新迭代,但是js的代码基本上却很少改动。
补充:Angular支持单元测试和e2e-testing。
AngularJS 在实际应用中缺点:
验证功能错误信息显示比较薄弱,需要写很多模板标签,没有jQuery Validate方便,所以我们自己封装了验证的错误信息提示;
ngView只能有一个,不能嵌套多个视图,虽然有 angular-ui/ui-router · GitHub 解决,但是貌似ui-router 对于URL的控制不是很灵活,必须是嵌套式的;
对于特别复杂的应用场景,貌似性能有点问题,特别是在Windows下使用chrome浏览器;
这没有完美兼容低版本,升级之后可能会导致一个兼容性的BUG;
ng提倡在控制器里面不要有操作DOM的代码,对于一些jQuery 插件的使用,如果想不破坏代码的整洁性,需要写一些directive去封装插件,但是现在有很多插件的版本已经支持Angular了;
Angular 太笨重了,没有让用户选择一个轻量级的版本,;
使用的人多才会暴露更多的问题,一起为这些问题寻找解决方案是一个社区的良性趋势,选择Angular,的确使开发效率大大提高。