Dependency injection using javascript / coffeescript to help test

I am doing some tests with Jasmine in my web application. I use Coffeescript to write models, services, and view models.

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

Now i am writing a jasmine test

 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() 

So the problem is that I have dependencies on alert and service in my viewModel . This makes tests annoying to write and maintain.

Are there libraries for dependency injection in Javascript. I used several .net libraries such as castle windsor and ninject .

Or should I just accept a template of a certain type. I have to say that I use knockout , and when I use the viewmodel in my actual application, it looks something like this.

 <script type="text/javascript"> $(function () { var viewModel = new MyViewModel(); ko.applyBindings(viewModel); }); </script> 

Instead of creating my own object, I would ask for an injection structure for an instance of MyViewModel , I assume.

I am looking for advice on which template or library to adopt, in order to make my testing a little easier and help decouple my javascript classes from each other.


Libs I found:

  • Wire - Only ECMA 5+ and I need to support older browsers
  • Dijon - It looks fine, but I haven't tried it yet.

EDIT: What I finished doing

  • I accepted RequireJs and moved all of my objects to AMD style modules.
  • I use Jamine to run tests.
  • I use Sinon to create mocks and stub
  • I use Squire to inject mocks and stubs into my test system.

See sample coffeescript file

 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) 
+4
source share
2 answers

You can use requirejs and one of the following solutions:

Or are you just mocking the prototypes of your objects.

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

Btw. you can use wire.js with your old browser using padding. From the docs:

To support legacy browsers other than ES5, wire.js 0.9.x requires poly 0.5.0 or higher. You can clone or load poly into your project, or install it through yeoman / bower:

+1
source

There is a library that provides very similar ninject functionality for Coffeescript, honk-di . It is useful to write about this here. Your example will become something like this:

 class MyViewModel elementId: inject('element.id') # Inject a constant alert: inject(Alert) service: inject(MyService) constructor: -> @alert.elementId = @elementId @service.alertId = @alert.elementId 

Then your tests will work the same as with ninject , Guice or similar. You describe your test objects in a module / binder and just ask the injector for your class during testing.

 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
source

Source: https://habr.com/ru/post/1483193/


All Articles