在Jest

时间:2017-08-13 08:46:45

标签: javascript unit-testing mocking jestjs

我真的非常挣扎于此,所以请非常感谢任何帮助......

我有一个ExternalDependency模块导出一个类。

TestSubject是另一个类模块 当实例化TestSubject时,ExternalDependency实例将在此内部合成。

出于测试目的,我想有选择地在模拟和真实版本的ExternalDependency类之间进行交换。

ExternalDependency.js

module.exports = class ExternalDependency {
  constructor () {
    this.isMocked = false
  }
}

TestSubject.js

const ExternalDependency = require('./ExternalDependency')

module.exports = class TestSubject {
  constructor () {
    this.externalDependency = new ExternalDependency()
  }

  isExternalDependencyMocked () {
    return this.externalDependency.isMocked
  }
}

Test.js

const TestSubject = require('./TestSubject')

const MockedExternalDependency = class ExternalDependency {
  constructor () {
    this.isMocked = true
  }
}

describe ('TestSubject', () => {
  it ('will require and instantiate the real ExternalDependency', () => {
    const testSubject = new TestSubject()
    expect(testSubject.isExternalDependencyMocked()).toEqual(false)
  })
  it ('or the mocked one here', () => {
    jest.mock('./ExternalDependency', MockedExternalDependency) 
        // Failing with: 
        // babel-plugin-jest-hoist: The second argument
        // of `jest.mock` must be a function.
    const testSubject = new TestSubject()
    expect(testSubject.isExternalDependencyMocked()).toEqual(true)
  })
  it ('and back to the real', () => {
    jest.unmock('./ExternalDependency')
    const testSubject = new TestSubject()
    expect(testSubject.isExternalDependencyMocked()).toEqual(false)
  })
})

好的,我知道这是错的 但是,我怎样才能实现类似的行为?

1 个答案:

答案 0 :(得分:0)

任何正在努力解决这个问题的人...... 刚刚用可能的解决方案醒来。

所以,首先让我们试着了解Jest的工作原理:

// __mock__/ExternalDependency.js
module.exports = 'MOCK'

// ExternalDependency.js
module.exports = 'REAL'

// TestSubject.js
module.exports = require('./ExternalDependency')

// TestSubject.spec.js
const TestSubject = require('./TestSubject')

describe ('TestSubject', () => {
  it ('will require the real ExternalDependency', () => {
    expect(TestSubject).toEqual('REAL')
  })
  it ('or the mocked one here', () => {
    jest.resetModules()
    jest.mock('./ExternalDependency')
    // This will work just fine:
    // jest.mock('./ExternalDependency', () => {return 'MOCK'})
    const TestSubjectMocked = require('./TestSubject')
    expect(TestSubjectMocked).toEqual('MOCK')
  })
  it ('and back to the real', () => {
    expect(TestSubject).toEqual('REAL')
  })
})

然后解决方案应该很简单:

// __mock__/ExternalDependency.js
module.exports = class ExternalDependency {
  constructor () {
    this.isMocked = true
  }
}

// ExternalDependency.js
module.exports = class ExternalDependency {
  constructor () {
    this.isMocked = false
  }
}

// TestSubject.js
const ExternalDependency = require('./ExternalDependency')

module.exports = class TestSubject {
  constructor () {
    this.externalDependency = new ExternalDependency()
  }

  isExternalDependencyMocked () {
    return this.externalDependency.isMocked
  }
}

// TestSubject.spec.js
const TestSubject = require('./TestSubject')

const mock = () => {
  return class ExternalDependency {
    constructor () {
      this.isMocked = true
    }
  }
}

describe ('TestSubject', () => {
  it ('will require and instantiate the real ExternalDependency', () => {
    const testSubject = new TestSubject()
    expect(testSubject.isExternalDependencyMocked()).toEqual(false)
  })
  it ('or the mocked one here', () => {
    jest.resetModules()
    jest.mock('./ExternalDependency')
    // This works fine too:
    // jest.doMock('./ExternalDependency', mock) // you really need doMock here!
    const TestSubjectMocked = require('./TestSubject')
    const testSubject = new TestSubjectMocked()
    expect(testSubject.isExternalDependencyMocked()).toEqual(true)
  })
  it ('and back to the real', () => {
    const testSubject = new TestSubject()
    expect(testSubject.isExternalDependencyMocked()).toEqual(false)
  })
})

也可以注入类声明:

// TestSubject.js
const ExternalDependency = require('./ExternalDependency')

module.exports = class TestSubject {
  constructor () {
    this.externalDependency = new ExternalDependency()
  }

  isExternalDependencyMocked () {
    return this.externalDependency.isMocked
  }

  isSpied() {
    this.externalDependency.isSpied()
  }
}

// TestSubject.spec.js
const spy = jest.fn()
const mock = (value) => {
  return () => {
    return class ExternalDependency {
      constructor () {
        this.isMocked = value
      }
      isSpied () {
        spy()
      }
    }
  }

}
jest.resetModules()
jest.doMock('./ExternalDependency', mock('MyMock'))
const ExternalDependencyMocked = require('./ExternalDependency')
const TestSubjectMocked = require('./TestSubject')

describe ('TestSubject', () => {
  it ('tested injected', () => {
    const testSubject = new TestSubjectMocked()
    expect(testSubject.isExternalDependencyMocked()).toEqual('MyMock')
    testSubject.isSpied()
    expect(spy).toHaveBeenCalled()
  })
})