Observable的简单测试结果是带有chai和mocha的nodejs

时间:2017-11-18 10:40:20

标签: node.js testing mocha rxjs rxjs5

我正在使用Nodejs,RxJS和Typescript开发一个应用程序。

该应用程序有一个函数,它返回一个字符串的Observable

myObsFunction() : Observable<string> {
... do stuff
}

我希望能够做一个简单的测试来检查当我订阅这个函数时,我得到了预期的字符串。我正在使用 chai mocha ,因此我编写了以下测试用例

import { expect } from 'chai';
import 'mocha';

import {myObsFunction} from './my-source-file';

describe('myObsFunction function', () => {

    it('check myObsFunction', () => {
        const expectedString = 'abc';
        let receivedString: string;
        myObsFunction().subscribe(
            data => receivedString = data,
            error => console.error(error),
            () => expect(receivedString).to.equal(expectedString)
        )
    });

});

不幸的是,这个测试用例并不像我预期的那样有效。它始终表现为即使出现错误也已成功通过。我在expect函数中编写的onCompleted检查即使在expectedString不等于receivedString时也没有发出任何信号。实际执行onCompleted函数(我可以看到这只是在console.log函数中添加onCompleted指令)但是当出现错误时期望不会发出任何错误

有没有办法在不必开始使用调度程序和更复杂的机制的情况下运行这样简单的测试?

1 个答案:

答案 0 :(得分:3)

测试逻辑听起来很合理,这是mocha和chai的一个工作示例。

&#13;
&#13;
console.clear() 
const Observable = Rx.Observable
mocha.setup('bdd');
const assert = chai.assert;
const should = chai.should();
const expect = chai.expect;
const done = mocha.done;


const myObsFunction = () => Observable.of('xyz');
const myAsyncObsFunction = () => Observable.timer(500).mapTo('xyz');

describe('RxJs Observable Test Examples', function() {

  it('should test the observable succeeds', function () {
    const expectedString = 'xyz';
    let receivedString: string;
    myObsFunction().subscribe(
      data => receivedString = data,
      error => console.error(error),
      () => {
        expect(receivedString).to.equal(expectedString);
      }  
    )
  });

  it('should test the observable fails', function () {
    const expectedString = 'abc';
    let receivedString: string;
    myObsFunction().subscribe(
      data => receivedString = data,
      error => console.error(error),
      () => {
        expect(receivedString).to.equal(expectedString);
      }  
    )
  });

  it('should test the async observable succeeds', function (done) {
    const expectedString = 'xyz';
    let receivedString: string;
    myAsyncObsFunction().subscribe(
      data => receivedString = data,
      error => console.error(error),
      () => {
        //expect(receivedString).to.equal(expectedString);
        if (receivedString !== expectedString) {
          return done(new Error("Failed match"));
        } else {
          return done();
        }
      }  
    )
  });

  it('should test the async observable fails', function (done) {
    const expectedString = 'abc';
    let receivedString: string;
    myAsyncObsFunction().subscribe(
      data => receivedString = data,
      error => console.error(error),
      () => {
        //expect(receivedString).to.equal(expectedString);
        if (receivedString !== expectedString) {
          return done(new Error("Failed match"));
        } else {
          return done();
        }
      }  
    )
  });
});

mocha.run();
&#13;
<link href="https://cdnjs.cloudflare.com/ajax/libs/mocha/2.3.4/mocha.min.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/chai/3.5.0/chai.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/mocha/2.3.4/mocha.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/5.5.2/Rx.js"></script>
<div id="mocha"></div>
&#13;
&#13;
&#13;


当observable从未触发时出现误报

如果观察者从不发射,我遇到的一件事就是假阳性。这是我用来克服这个问题的一些辅助函数。请注意take(1)确保触发已完成的事件,即使observable本身不完整也是如此。

&#13;
&#13;
console.clear() 
const Observable = Rx.Observable
mocha.setup('bdd');
const assert = chai.assert;
const should = chai.should();
const expect = chai.expect;

const subscribeAndTestValue = function (observable: Observable<any>, expected: any): string {
  let fail = '';
  let wasSubscribed = false;
  const sub = observable
    .take(1)
    .subscribe(
      (result) => {
        if (result !== expected) {
          fail = 'Subscription result does not match expected value';
        }
        wasSubscribed = true;
      },
      (error) => {
        fail = 'Subscription raised an error';
      },
      (/*completed*/) => {
        // When testing a single value,
        // need to check that the subscription was activated,
        // otherwise the expected value is never tested
        if (!wasSubscribed) {
          fail = 'Subscription produced no results';
        }
      }
    );
  sub.unsubscribe();
  return fail;
}

const subscribeAndTestNoDataEmitted = function (observable: Observable<any>): string {
  let fail;
  let wasSubscribed = false;
  const sub = observable
    .subscribe(
      (result) => {
        wasSubscribed = true;
      },
      (error) => {
        fail = 'Subscription raised an error';
      },
      (/*completed*/) => {
        if (wasSubscribed) {
          fail = 'Subscription produced values when none were expected';
        }
      }
    );
  sub.unsubscribe();
  return fail;
}

const emptyObservable = Observable.empty();
const nonCompletingObservable = Observable.interval(1000);
const emittingObservable = Observable.of('abc');

describe('RxJs Observable Test Examples', function() {

  it('should test the observable fires', function () {
    const expectedString = 'xyz';
    const failed = subscribeAndTestValue(emptyObservable, expectedString);
    expect(failed).to.equal('Subscription produced no results');
  });

  it('should test first observable value of a non-completing observable', function () {
    const expectedString = '0';
    const failed = subscribeAndTestValue(nonCompletingObservable, expectedString);
    expect(failed).to.equal('');
  });

  it('should test the observable does not fire', function () {
    const expectedString = 'xyz';
    const failed = subscribeAndTestNoDataEmitted(emittingObservable, expectedString);
    expect(failed).to.equal('Subscription produced values when none were expected');
  });
  
});

mocha.run();
&#13;
<link href="https://cdnjs.cloudflare.com/ajax/libs/mocha/2.3.4/mocha.min.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/chai/3.5.0/chai.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/mocha/2.3.4/mocha.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/5.5.2/Rx.js"></script>
<div id="mocha"></div>
&#13;
&#13;
&#13;