【问题标题】:Mocking external class dependencies within Jest在 Jest 中模拟外部类依赖项
【发布时间】:2018-01-21 08:32:23
【问题描述】:

我真的很挣扎,所以请任何形式的帮助都非常感谢....

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

TestSubject 是另一个类模块。
当 TestSubject 将被实例化时,一个 ExternalDependency 实例将被复合到 this 中。

出于测试目的,我想选择性地在模拟版本和真实版本的 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)
  })
})

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

【问题讨论】:

    标签: javascript unit-testing mocking jestjs


    【解决方案1】:

    致所有为此苦苦挣扎的人...
    刚刚醒来可能的解决方案。

    所以,首先让我们尝试了解 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()
      })
    })
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-01-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-10-17
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多