如何解决如何在方法中测试订阅
考虑这个角度分量:
export class CheckoutComponent {
constructor(private paymentService: PaymentService,private paymentModalService: PaymentModalService) {}
public onCheckout(): void {
const paymentStatus$: Observable<string> = this.paymentService.getStatus();
const paymentrequired$ = paymentStatus$.pipe(map(paymentStatus => paymentStatus === 'INCOMPLETE'));
paymentrequired$.subscribe(() => {
this.paymentModalService.open();
});
}
}
我正在尝试编写一个 jasmine 测试来确认调用了 paymentModalService.open()
:
import { cold } from 'jasmine-marbles';
describe('CheckoutComponent',() => {
let component: CheckoutComponent;
let mockPaymentService: jasmine.SpyObj<PaymentService>;
let mockPaymentModalService: jasmine.SpyObj<PaymentModalService>;
beforeEach(() => {
mockPaymentService = jasmine.createSpyObj(['getStatus']);
mockPaymentModalService = jasmine.createSpyObj(['open']);
component = new CheckoutComponent(mockPaymentService,mockPaymentModalService);
});
it('should open payment modal if required',() => {
mockPaymentService.getStatus.and.returnValue(cold('a',{ a: 'INCOMPLETE' }));
component.onCheckout();
expect(mockPaymentModalService.open).toHaveBeenCalled(); // FAIL: was never called
});
});
在断言方法已被调用之前,有没有办法等待冷测试 observable 完成发射?
我曾尝试使用 fakeAsync
和 tick
,但似乎都无济于事。我意识到它适用于 of()
而不是 TestColdobservable
,但我希望对可观察行为进行更精细的控制。我真的不打算完成 getStatus()
observable。
解决方法
您的主要问题是:
我想要对可观察行为进行更精细的控制。我真的不打算完成 getStatus() observable。
如果你不想完成它,那么它本质上不是一个冷的 observable,而是一个热的 observable,这意味着你可以创建一个主题并通过
var sub = new Subject();
mockPaymentService.getStatus.and.returnValue(sub.asObservable());
// run method and let it subscribe
component.onCheckout();
// fire it
sub.next('a',{ a: 'INCOMPLETE' });
expect(mockPaymentModalService.open).toHaveBeenCalled();
我建议您阅读有关如何编写组件测试用例的文档: Angular guide to writing test cases
问题: 在您当前的测试方法中,您将无法运行组件生命周期,而是手动运行它们并跳过实际测试用例。 它适用于服务,但不适用于组件。
,让我建议你一些东西,这不是你的问题的重点,但无论如何都可以提供帮助。
我的建议是将逻辑从组件转移到服务。
查看您的代码,似乎 CheckoutComponent
需要一个可观察的 paymentRequired$
,它会在需要付款时发出通知。
让我们假设 this.paymentService.getStatus()
是对后端 API 的调用,它返回付款状态。在这种情况下,我会在服务中做的事情是这样的
export class PaymentService {
constructor(http,...)
// Private Subjects - using Subject to notify allows multicasting
private _paymentRequired$ = new Subject<boolean>();
// Public API Streams
public paymentRequired$ = this._paymentRequired$.asObservable();
// Public API methods
public getStatus() {
this.http.get(....).pipe(
tap({
next: resp => this._paymentRequired$.next(resp === 'INCOMPLETE'),error: err => {// manage the error case}
})
)
}
}
如果你像这样将逻辑移到服务上,那么CheckoutComponent
可以简单地订阅paymentService.paymentRequired$
在其ngOnInit
方法中的observable,并且测试只能处理服务而不是组件。
特别是测试必须以某种方式实例化服务、订阅 paymentRequired$
可观察对象、调用 getStatus()
并检查 paymentRequired$
是否已通知。
阅读关于 component marble tests 的文档,我发现我需要像这样刷新测试调度程序:
import { cold,getTestScheduler } from 'jasmine-marbles';
it('should open payment modal if required',() => {
mockPaymentService.getStatus.and.returnValue(cold('a',{ a: 'INCOMPLETE' }));
component.onCheckout();
getTestScheduler().flush(); // <=== prompt the scheduler to execute all of its queued actions
expect(mockPaymentModalService.open).toHaveBeenCalled(); // SUCCESS
});
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。