我有一个 Javascript 模块,它从另一个模块访问 Promise 对象,然后将其转换为自己使用。我正在使用Bluebird确保所有 Promise 处理程序都是异步调用的库。这对于测试来说是一个很大的问题,特别是当内部 promise 没有公开时。
module.exports = (testedModule, app) ->
app.module('otherModule').somePromise.then transformValue
transformValue = (val) ->
return new Extra.TransformedValue(val)
在测试中,我 mock 第一个 promise ,所以我可以访问它。第二个 promise 保留在模块内部,我不想仅仅为了测试而公开它。请注意,我使用的是 Mocha+Chai+Sinon。
beforeEach ->
@initModule = -> app.module('testedModule', testedModule) # prepare function to initialize tested module
@dfd = dfd = Promise.defer() # defer promise resolution to tests
app.module 'otherModule', (otherModule) ->
otherModule.somePromise = dfd.promise
@transformSpy = sinon.spy Extra, 'TransformedValue' # spy on the constructor function
@promiseTransform = dfd.promise.then =>
# this usually fails as the spy is called more then once due to async nature of the tests
@transformSpy.should.have.been.calledOnce
# promise gets resolved with the return value of the spy
# thus it should contain created instance of the TransformedValue
return @transformSpy.firstCall.returnValue
afterEach ->
@transformSpy.restore()
每次测试的一些准备。只需使用 promiseTransform
,在每个测试中分别使用 dfd.resolve()
即可解决。然而,transformSpy 本身附加到所有测试共享的全局对象(也许也应该被 stub )。大多数测试如下所示:
it 'should test whatever...', ->
@init() # initialize module
# something else is tested here, doesn't matter
# note that @dfd is not resolved here, thus transformValue is not called yet
这工作得很好,但随后进行了实际解析 dfd 的测试,这里一切都变得困惑。有时 spy 会被多次解决或根本没有解决。这是非常令人困惑的异步操作竞赛。
it 'should instantiate TransformedValue with correct argument', (done) ->
expected = {foo: "bar"}
@promiseTransform.then (transformed) =>
# test here that TransformedValue constructor has been called once
# ... it actually FAILS, because it was called twice already!
@transformSpy.withArgs(expected).should.have.been.calledOnce
transformed.should.be.an.instanceof Extra.TransformedValue
# somehow this resolves promise for previous test and
# it causes `transformValue` to be called back there
@dfd.resolve expected
@init()
我在这上面花了大约两天的时间,这已经让我抓狂了。测试应该是一个工具和实际的代码来创建。我可能错过了一些明显的解决方案。
您是否有任何一般(或具体)提示如何以更少的困惑和更多的控制和确定性来处理这个问题?目前我正在考虑对整个 Promise 进行 stub 以使其真正同步。但在我看来,这有点使测试无效,因为工作流程可能与实际运行中的工作流程不同。
最佳答案
spy 怎么了?如果这是同步代码,您就不会使用 spy 。如果一切都是同步的,您将如何编写测试?
为什么不将测试编写为:
it('should instantiate TransformedValue with correct argument', function() {
var expected = {};
return transform(expected).then(function(val) {
assert.deepEqual(Extra.TransformedValue.value, expected)
assert(val instanceof Extra.TransformedValue);
});
});
关于javascript - 如何在单元测试中处理嵌套异步操作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23593674/