在Ava测试中使用RxJS延迟算子

时间:2017-09-11 06:17:12

标签: javascript rxjs ava

我是JavaScript程序的作者,需要针对大量测试执行。我发现每个测试都遵循类似的格式,因此使用工厂函数生成测试是合适的。

工厂函数名为testFactory,如下面的代码所示。它使用数据数组调用,一旦我的应用程序逻辑被添加,它将指示工厂如何构建特定的测试。工厂功能也负责执行测试。

我选择了RxJS,以便在延迟时间内延迟两秒钟。 string包含在传递给工厂的数据中。 (我之前的尝试 实现使用了promises,但是我没有使这种方法有效。)正如你所看到的,这是通过使用Rx延迟运算符来实现的。

选择Ava是因为它有与RxJS合作的声誉。正如您所看到的,我通过订阅我的观察结果来调用Rx主题。

在我的实际应用程序代码中,此订阅调用实现我的应用程序逻辑的状态机,并且通过在状态的回调方法中调用主题的下一个方法将来自状态机的数据馈送到主题中机。这就是为什么我不能简单地将我的observable直接插入Ava测试方法,而是必须经历一个主题。选择一个主题而不是一个可观察主体的能力,允许主体从其定义之外调用其下一个和完整的方法。

我已从下面的代码中删除了我的应用程序逻辑,以免将问题与这些细节混淆。问题来自“延迟”。字符串从数据数组中删除。当使用不包含延迟的数据运行此代码时,测试不会通过:

const data = [
  { r: 'c' },
  { l: 'c' },
  { l: 'n' },
  { l: 'c' }
];

它失败了:Test finished without running any assertions.

如果没有“延迟”,我该如何通过?在数据数组中?为什么在没有“延迟”的情况下会失败?在数据阵列中?谢谢。

const ava = require('ava');
const { test } = ava;

const Rx = require('rxjs/Rx');
const { Observable, Subject } = Rx;

const data = [
  { r: 'c' },
  { l: 'c' },
  { l: 'n' },
  'delay',
  { l: 'c' }
];

const testFactory = (data) => {
  let subject = new Subject();

  // This code adds a delay property to each item which passes through, adding a
  // delay value based on a cumulative delay value maintained by the scan
  // operator. Items which are simply delays are marked with a 'skip' property
  // in the scan and skipped in the flatMap. Once the delay has been performed
  // by the delay operator, the added delay property is deleted. If there is a
  // simpler way in Rx to achieve this functionality, I'm open to suggestions
  // on refactoring this code. :-)
  const source = Observable.from(data)
    .scan((acc, val) => {
      if (val === 'delay') {
        return { skip: true, delay: acc.delay + 2000 };
      }
      return Object.assign(val, { delay: acc.delay });
    }, { delay: 0 })
    .flatMap((e) => {
      if (e.skip) {
        return Observable.empty();
      } else {
        return Observable.of(e)
          .delay(e.delay)
          .map(e => { delete e.delay; return e; });
      }
    });

  // This is the subscribe block which in my application called my state
  // machine. Since the state machine has been removed, the Subject is called
  // directly, instead of calling it from the callback tot the state machine.
  // Either way, the same problem exists. 
  source
    .subscribe({
      next: e => {
        subject.next(e);
      },
      complete: () => {
        subject.complete();
      }
    });

  // This test always passes. When the 'delay' is removed, the failure would
  // indicate to me that its never called.  
  test('', t => {
    // t.plan(1);
    return subject
      .map((n) => {
        t.true(true);
      });
  });
};

testFactory(data);

注意:有趣的是,当Ava的导入与导入Ava测试函数的下面的行一起被删除,并且对该主题的常规RxJS订阅替换了对测试函数的调用时,代码可以正常工作无论有没有延迟'数据结构中的字符串:

  // test('', t => {
  //   // t.plan(1);
  //   return subject
  //     .map((n) => {
  //       t.true(true);
  //     });
  // });

  subject.subscribe((v) => {
    console.log(JSON.stringify(v));
  });

这表明问题出在我使用Ava上吗?

1 个答案:

答案 0 :(得分:0)

我对RxJS,观察者或主题并不十分熟悉,但Test finished without running any assertions.

中有一条线索

当您返回可观察,承诺或使用test.cb(t => t.end())时,AVA测试可以是同步的,也可以是异步的。如果在测试结束前没有运行断言,AVA也会失败测试。

在您的情况下,看起来AVA已确定您的测试是同步的。您应该确保它是异步的,并且只有在数据被完全消耗时才结束它。