【问题标题】:the use of the RxJS delay operator within Ava tests在 Ava 测试中使用 RxJS 延迟运算符
【发布时间】:2017-09-11 06:17:12
【问题描述】:

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

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

如果传递给工厂的数据中包含“延迟”字符串,我选择 RxJS 是为了实现两秒延迟。 (我之前的尝试 实现使用了 Promise,但我未能让这种方法发挥作用。)如您所见,这是通过使用 Rx 延迟运算符完成的。

选择 Ava 是因为它在与 RxJS 合作方面享有盛誉。如您所见,我正在通过订阅我的 observable 调用 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 的问题上?

【问题讨论】:

    标签: javascript rxjs ava


    【解决方案1】:

    我对 RxJS、observables 或主题不是很熟悉,但在 Test finished without running any assertions. 中有一个线索

    当你返回一个 observable、promise 或使用 test.cb(t => t.end()) 时,AVA 测试可以是同步的或异步的。如果在测试完成之前没有运行任何断言,AVA 也会失败测试。

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-12-12
      • 2018-05-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-01-13
      • 1970-01-01
      相关资源
      最近更新 更多