为什么在Angular2测试中使用BehaviorSubject作为间谍而不是普通的Subject

时间:2017-03-08 11:38:02

标签: testing rxjs

我参考了以下博文:https://vsavkin.com/three-ways-to-test-angular-2-components-dcea8e90bd8d#.he4b4rw65

在其中一项测试中(见下文),BehaviorSubject用于充当间谍

我理解SubjectObservable + Observer)的要求,但为什么要使用BehaviorSubject代替普通Subject

有人可以解释一下吗?

describe('ComposeCmp', () => {
  let actions: BehaviorSubject<any>;
  let time: CurrentTime;

  beforeEach(() => {
    // this subject acts as a "spy"
    actions = new BehaviorSubject(null);

    // dummy implementation of CurrentTime
    time = () => '2016-08-19 9:10AM';
  });

  it('emits a reply action on submit', () => {
    // a fake activated route
    const route = {
      snapshot: {
        root: {
          firstChild: { params: { id: 11 } }
        }
      }
    };
    const c = new ComposeCmp(<any>route, time, actions);

    // performing an action
    c.form.setValue({
      title: 'Categorical Imperative vs Utilitarianism',
      body: 'What is more practical in day-to-day life?'
    });
    c.onSubmit();

    // reading the emitted value from the subject
    // to make sure it matches our expectations
    expect(actions.value.conversationId).toEqual(11);
    expect(actions.value.payload).toEqual({
      title: 'Categorical Imperative vs Utilitarianism',
      body: 'What is more practical in day-to-day life?',
      createdAt: '2016-08-19 9:10AM'
    });
  });
});

编辑:我有一个进一步的询问:actions BehaviorSubject订阅了什么,订阅者是什么?被测组件如下:

@Component({moduleId: module.id, templateUrl: 'compose.html'})
class ComposeCmp {
  form = new FormGroup({
    title: new FormControl('', Validators.required),
    body: new FormControl('')
  });

  constructor(private route: ActivatedRoute,
              private currentTime: CurrentTime,
              private actions: Actions) {}

  onSubmit() {
    const routerStateRoot = this.route.snapshot.root;
    const conversationRoute = routerStateRoot.firstChild;
    const conversationId = +conversationRoute.params['id'];

    const payload = Object.assign({},
      this.form.value,
      {createdAt: this.currentTime()});

    this.actions.next({
      type: 'reply',
      conversationId: conversationId,
      payload: payload
    });
  }
}

1 个答案:

答案 0 :(得分:2)

实际上非常简单:)

在测试间谍时,您可以跟踪。意思是,你可以问一下间谍的事情,比如&#34;你的价值是什么&#34;,&#34;你被称为&#34;或者&#34;你用什么参数调用了#34;。

在你的情况下,间谍充当动作流的模拟(但我猜你已经知道了)。

主题 BehaviorSubject 之间的差异最好显示在如下的简单示例中:

&#13;
&#13;
const s = new Rx.Subject();
s.next(5);
console.log('Subject:', s.value);

const bs = new Rx.BehaviorSubject();
bs.next(5);
console.log('BehaviorSubject:', bs.value);
&#13;
<script src="https://unpkg.com/rxjs/bundles/Rx.min.js"></script>
&#13;
&#13;
&#13;

tl; dr; BehaviorSubject 存储其最新值,您可以通过.value获取。 主题不存储任何内容。在测试中,您需要验证是否将正确的数据(.next())推送到操作流(actions)。使用BehaviorSubject,您可以对此进行测试。

为什么不需要订阅者?

这是因为调用next()也会设置value。请参阅BehaviorSubject的源代码:

next(value: T): void {
  super.next(this._value = value);
}