组件集成测试与茉莉花间谍返回可订阅



我正在尝试进行组件集成测试(即包括 Angular 生命周期事件),但我很难嘲笑 Jasmine 的服务,一个公开Subscribable的服务。

重现我的方案:

  1. ng new ng-comp-tests
  2. ng generate component my-screen
  3. ng generate service crud
  4. ng generate class item

将类更新为:

export class Item {
constructor(public name: string) { }
}

然后使服务如下所示:

export class CrudService {
private thing = new Subject<Item>();
constructor() {
setInterval(() => { this.thing.next(new Item('Thing ' + Math.random())); }, 1000);
}
getThingObservable() {
return this.thing.asObservable();
}
}

将组件更改为如下所示(并将其作为应用程序组件的主要内容包含在内):

<p *ngIf="!!thing">{{thing.name}}</p>
export class MyScreenComponent implements OnInit, OnDestroy {
public thing: Item;
private thingSubscription: Subscription;
constructor(private service: CrudService) { }
ngOnInit() {
this.thingSubscription = this.service
.getThingObservable()
.subscribe(t => { this.thing = t; });
}
ngOnDestroy(): void {
this.thingSubscription.unsubscribe();
}
}

最后,将规范更改为:

describe('MyScreenComponent', () => {
let component: MyScreenComponent;
let fixture: ComponentFixture<MyScreenComponent>;
beforeEach(async(() => {
const serviceSpy = jasmine.createSpyObj('CrudService', {
getThingObservable: () => new Subject<Item>().asObservable()
});
TestBed.configureTestingModule({
declarations: [ MyScreenComponent ],
providers: [ { provide: CrudService, useValue: serviceSpy } ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(MyScreenComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

这将为测试提供例外:

MyScreenComponent 应该创建
[object ErrorEvent] thrown

该异常并没有真正的帮助,Chrome 的控制台也没有帮助,因为它显示了以下缩写日志:

  • "无法加载 ng:///DynamicTestModule/...ngfactory.js:跨源请求...">
  • "无法加载 ng:///DynamicTestModule/...ngfactory.js:跨源请求...">
  • "未捕获的穹顶:无法执行'发送'....">
  • "清理组件时出错...无法读取未定义的属性"取消订阅"...">

相关问题的最佳答案表明我忘记做fixture.detectChanges()(这可以防止ngOnInit触发),但正如你所看到的,我的代码中确实有这个。

这里一定还有其他问题,但是什么?

答案就在jasmine.createSpyObj(...)文档中,说明了第二个参数(强调我的):

要为其创建间谍的方法名称数组,或Object,其键将是方法名称和值 returnValue

在你的代码中,你为getThingObservable提供了一个虚假的实现,如下所示:

getThingObservable: () => new Subject<Item>().asObservable()

这样,getThingObservable间谍将在组件调用它时返回一个 lambda,该 lambda没有组件尝试执行的subscribe,因此ngOnInit完全失败。ngOnDestroy仅作为次要效果失败。

相反,您应该直接传递 returnValue,如下所示:

getThingObservable: new Subject<Item>().asObservable()

然后,当组件调用getThingObservable时,它将获得实际的可观察量,并且事情会很好。

附言。您也可以简化为使用{ of } from 'rxjs/observable/of'

getThingObservable: of<Item>()

最后,您还可以求助于大理石测试,以更好地控制测试中的可观察量。

最新更新