0

我是需要针对许多测试执行的 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 订阅,代码在有和没有 'delay 的情况下都有效' 数据结构中的字符串:

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

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

这是否表明问题出在我对 Ava 的使用上?

4

1 回答 1

0

我对 RxJS、可观察对象或主题不是很熟悉,但有一个线索Test finished without running any assertions.

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

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

于 2017-09-17T13:00:46.887 回答