【问题标题】:Dependency Injection with javascript / coffeescript to aid testability使用 javascript/coffeescript 进行依赖注入以帮助可测试性
【发布时间】:2013-05-23 16:29:28
【问题描述】:

我正在我的网络应用程序中使用Jasmine 进行一些测试。我正在使用Coffeescript 来编写我的模型、服务和视图模型。

class MyViewModel
  constructor: ( @options ) ->
    @alert = new Alert
      elementId: 'my-alert-element-id'

    @service = new MyService
      alertId: @alert.elementId

现在我用 jasmine 写一个测试

describe 'MyViewModel', ->
  sut = null

  beforeEach ->
    sut = new MyViewModel()

  afterEach ->
    sut = null

  describe 'constructor()', ->
    it 'creates a new instance of the ViewModel', ->
      expect( sut ).not.toBeNull()

所以这里的问题是我的viewModel 依赖于alertservice。这使得测试的编写和维护很烦人。

是否有用于 Javascript 中的依赖注入的库。我使用了几个.net 库,例如castle windsorninject

或者我应该只是采用某种类型模式。我应该说我正在使用knockout,当我在实际应用程序中使用视图模型时,它看起来像这样。

<script type="text/javascript">

  $(function () {
    var viewModel = new MyViewModel();
    ko.applyBindings(viewModel);
  });

</script>

我不会创建自己的对象,而是向注入框架询问 MyViewModel 我假设的实例。

我正在寻找有关采用哪种模式或库的建议,以使我的测试更容易一些,并帮助我的 javascript 类彼此分离。


我找到的库:

  • Wire - 只有 ECMA 5+,我需要支持旧版浏览器
  • Dijon - 看起来不错,但我还没试过。

编辑:我最终做了什么

  • 我采用了 RequireJs 并将我的所有对象移动到 AMD 样式模块中
  • 我使用 Jamine 运行测试
  • 我使用 Sinon 创建模拟和存根
  • 我使用 Squire 将模拟和存根注入到我的测试系统中

查看测试文件的coffeescript示例

define ['squire', 'sinon' ], ( squire, sinon ) ->
  describe '==== a view model ====', ->
    sut = null
    testContext = null

    beforeEach ->
      testContext =
        squireInjector: new squire
        stubService: sinon.stub()
        stubJquery: sinon.stub()
        someCallbackSpy: sinon.spy()

      testContext.squireInjector.mock( 
        'jquery', squire.Helpers.returns( stubJquery ) )

      testContext.squireInjector.require ['aViewModel'], ( viewModel ) =>
        sut = new viewModel
          service: testContext.stubService
          someCallback: testContext.someCallbackSpy

      waitsFor( -> sut? )

    afterEach ->
      sut = null
      testContext = null

    describe 'the constructor method should', ->
      it 'create a new instance of the view 
        model and have required dependencies', ->
        expect( sut ).toBeDefined
        expect( sut.service ).toBeDefined
        expect( sut.someCallback ).toBeDefined

    describe 'the next method should', ->
      it 'increment the route id by one', ->
        # Arrange
        sut.routeId = 5

        # Act
        sut.next()

        # Assert
        expect( sut.routeId ).toEqual( 6 )
        expect( testContext.someCallbackSpy.called ).toBe(true)

【问题讨论】:

  • 写得好!谢谢
  • Jasmine 还支持创建模拟和存根。诗浓有什么具体原因吗?

标签: javascript unit-testing dependency-injection coffeescript jasmine


【解决方案1】:

有一个库为 Coffeescript 提供了与 ninject 非常相似的功能,honk-diHere's a helpful write up 关于它。您的示例将变得更像这样:

class MyViewModel
  elementId:  inject('element.id') # Inject a constant
  alert:      inject(Alert)
  service:    inject(MyService)

  constructor: ->
    @alert.elementId = @elementId
    @service.alertId = @alert.elementId

然后,您的测试将与 ninjectGuice 或类似的一样工作。您在模块/绑定器中描述您的测试对象,并在测试时简单地向注入器询问您的类。

describe 'MyViewModel', ->
  sut = null

  beforeEach ->
    # Assuming you've made mocks or simplified classes for
    # Alert and MyService which are set up in TestModule.
    # `element.id` will also need a definition.
    injector = new inject.Injector(new TestModule())
    sut = injector.getInstance(MyViewModel)

  afterEach ->
    sut = null

  describe 'constructor()', ->
    it 'creates a new instance of the ViewModel', ->
      expect( sut ).not.toBeNull()

【讨论】:

    【解决方案2】:

    您可以使用 requirejs,以及以下解决方案之一:

    或者你只是模拟你的对象的原型。

    jasmine.spy(Alert.prototype, 'someFunction')
    

    顺便说一句。您可以使用 shim 将wire.js 与旧版浏览器一起使用。来自文档:

    为支持非 ES5 旧版浏览器,wire.js 0.9.x 需要 poly 0.5.0 或更高。您可以克隆或下载 poly 到您的项目中,或者 通过 yeoman/bower 安装它:

    【讨论】:

    • 是否需要完全重写我的所有 js 才能在他们的框架下工作?
    • 任何解决方案都会出现这种情况,但是由于您使用的是可以在 requirejs 模块中简单转换的咖啡脚本类,因此工作量应该不大。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多