Unit testing in Typescript with dependency injection

I am having problems with typescript during unit testing. I am trying to unit test a module, for example the following code example:

import {Express} from 'express'

export interface BootClassInterface {
  setup(): Express
}

export class BootClass implements BootClassInterface {

  constructor(private express: () => Express ){

  }

  public test(){
      const app = this.express()
      app.get("/test", (req, res) => {
        res.send("Hello World")
      })

      return app;
  }
}

      

For testing, let's say I want to know if () was expressed. get () was called and if the first parameter was "/ test". Before switching to typescript, I always used the sinonJS module to spy on or stub out functionality so that I could test a certain dependency was being used correctly. Now with typescript I am having problems with the strong types that I have set in the module. Example:

import * as chai from 'chai'
import 'mocha'
import * as sinon from 'sinon'
import * as express from 'express'

import * as Boot from '../../src/Core/Boot'

const assert = chai.assert

suite('[CORE] unit test /Core/Boot.ts', () => {
  let BootClass: Boot.BootClassInterface

  setup(() => {
    const expressApp = () => {
      const app = express()
      app.get = sinon.spy()
      return app
    }

    const Services: Boot.BootServicesInterface = { express: expressApp }
    BootClass = new Boot.BootClass(Services)

  })

  test('Do first test', () => {
    const app = BootClass.setup()
    chai.assert.equal(app.get.called, 1)
  })
})

      

The above code example shows the following typescript compilation error:

error TS2339: Property 'called' does not exist on type 'ApplicationRequestHandler<Express>'.

      

I can see why typescript is returning this error and for some reason it is even obvious. I even know a possible solution in which I accept Express as any in the module.

But I'm looking for a more elegant way to be able to spy / stub / mock my dependencies for testing, but still have the benefits of strong typing.

+3


source to share


1 answer


As you stated, you are specifying Express

as a return type in the interface BootClassInterface

. So it app

will count Express

and it will look for its properties instead of your layout.

You can also just specify one property app

as any

. Try:

 chai.assert.equal((<any>app.get).called, 1)

      



Or using the Sinon type definition:

 chai.assert.equal((<SinonSpy>app.get).called, 1)

      

+1


source







All Articles