代码之家  ›  专栏  ›  技术社区  ›  Flame_Phoenix

如何剪短绒毛?

  •  1
  • Flame_Phoenix  · 技术社区  · 6 年前

    背景

    我正试图将一段代码片段从一个好的旧承诺转换成一个使用flutures和canvatory的东西:

    https://codesandbox.io/embed/q3z3p17rpj?codemirror=1

    问题

    现在,通常,使用承诺,我可以使用类似 sinonjs 拒绝承诺,即伪造结果、强迫解决、拒绝等。

    这是最基本的,因为它有助于测试多个分支方向,并确保一切按预期工作。

    然而,对于Flutures,情况就不同了。一个人不能简单地吹笛子,我也找不到 中国式 也可以提供帮助的库。

    问题

    1. 你是如何消除虱子的?
    2. 是否有任何具体的建议来做带绒毛/避难所的TDD?
    2 回复  |  直到 6 年前
        1
  •  1
  •   Zbigniew Zagórski    6 年前

    我不确定,但是那些绒毛(这个名字!…无论如何,API看起来很酷)是简单的对象,就像承诺一样。它们只有更复杂的API和不同的行为。

    此外,你可以很容易地用 Future.of , Future.reject 而不是做一些真正的API调用。

    是的,Sinon含有像 resolves , rejects 但它们只是包装器,可以用 callsFake .

    所以,您可以很容易地创建存根来创建这样的绒毛。

    someApi.someFun = sinon.stub().callsFake((arg) => {
        assert.equals(arg, 'spam');
        return Future.of('bar');
    });
    

    然后您可以像其他任何API一样测试它。 唯一的问题是“异步性”,但这可以像下面提出的那样得到解决。

    // with async/await
    it('spams with async', async () => {
        const result = await someApi.someFun('spam).promise();
        assert.equals(result, 'bar');
    });
    
    // or leveraging mocha's ability to wait for returned thenables
    it('spams', async () => {
        return someApi.someFun('spam)
            .fork(
                 (result) => { assert.equals(result, 'bar');},
                 (error) => { /* ???? */ }
            )
            .promise();
    });
    
        2
  •  0
  •   Beanow Alana Storm    6 年前

    正如Zbigniew建议的那样, Future.of Future.reject 是使用简单的旧JavaScript或任何您喜欢的工具或框架进行模拟的最佳候选者。

    要回答问题的第2部分,任何具体的建议如何用fluture做TDD。当然没有 唯一应该做的事 . 但是,如果您计划在整个应用程序中使用Futures,那么我建议您在可读性和编写测试方面投入一些时间。

    这适用于您经常在测试中包括的任何内容,而不仅仅是未来。 其思想是,当您浏览测试用例时,您将看到开发人员的意图,而不是让您的测试做您需要它们做的事情的样板文件。

    在我的例子中,我使用的是BDD风格的摩卡&柴(在当时提供)。 为了可读性,我创建了这些助手函数。

    const {expect} = require('chai');
    
    exports.expectRejection = (f, onReject) =>
        f.fork(
            onReject,
            value => expect.fail(
                `Expected Future to reject, but was ` +
                `resolved with value: ${value}`
            )
        );
    
    exports.expectResolve = (f, onResolve) =>
        f.fork(
            error => expect.fail(
                `Expected Future to resolve, but was ` +
                `rejected with value: ${error}`
            ),
            onResolve
        );
    

    正如你所看到的,没有什么神奇的事情发生,我只是失败了意想不到的结果,让你处理预期的路径,用它做更多的断言。

    现在,一些测试如下:

    const Future = require('fluture');
    const {expect} = require('chai');
    const {expectRejection, expectResolve} = require('../util/futures');
    
    describe('Resolving function', () => {
        it('should resolve with the given value', done => {
            // Given
            const value = 42;
            // When
            const f = Future.of(value);
            // Then
            expectResolve(f, out => {
                expect(out).to.equal(value);
                done();
            });
        });
    });
    
    describe('Rejecting function', () => {
        it('should reject with the given value', done => {
            // Given
            const value = 666;
            // When
            const f = Future.of(value);
            // Then
            expectRejection(f, out => {
                expect(out).to.equal(value);
                done();
            });
        });
    });
    

    跑一次,失败一次。

      ✓ Resolving function should resolve with the given value: 1ms
      1) Rejecting function should reject with the given value
    
      1 passing (6ms)
      1 failing
    
      1) Rejecting function
           should reject with the given value:
         AssertionError: Expected Future to reject, but was resolved with value: 666
    

    请记住,这应该被视为 异步代码 . 这就是为什么我总是接受 done 函数作为参数 it() 在我期望的结果结束时称之为它。或者,您可以更改助手的功能来返回一个承诺,并让Mocha处理它。