[英]Jasmine/Karma testing Angular 5 HTTP responses
我对TDD完全陌生,我正在尝试调试公司中正在使用的Angular 5大应用程序。
该应用程序运行良好,但是现在我必须实施测试,并且在创建最基础和入门的软件时我正在学习这些东西。 我已经为主要模块编写了这些东西,只是为了尝试这个工具:
describe('AppComponent', () => {
let httpClientSpy: { get: jasmine.Spy }
let dataReq: DataRequester;
let queryBuilder: PanelQueryBuilder;
let query: DataQuery;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [
MainComponent,
Menu,
MessageViewer
],
imports: [
BrowserModule,
BrowserAnimationsModule,
routing,
AngularFontAwesomeModule,
FormsModule,
HttpModule,
ChartModule,
Ng4LoadingSpinnerModule.forRoot(),
NgbModule.forRoot()
],
providers: [
ReactiveService,
DataRequester,
{ provide: APP_BASE_HREF, useValue : '/' }
]
}).compileComponents();
}));
it('should create the app', async(() => {
const fixture = TestBed.createComponent(MainComponent);
const app = fixture.debugElement.componentInstance;
expect(app).toBeTruthy();
}));
it('userType should be defined', async(()=>{
expect(MainComponent.userType).toBeDefined();
}))
it('DataRequester exists and retrieves info', async(()=>{
beforeEach(() => {
// TODO: spy on other methods too
httpClientSpy = jasmine.createSpyObj('HttpClient', ['get']);
dataReq = new DataRequester(<any> httpClientSpy);
queryBuilder = new PanelQueryBuilder();
});
expect(MainComponent).toBeDefined();
}))
it('1. Build query and check integrity', async()=>{
query = queryBuilder.buildInitialQuery("panel", "conversions", 144);
expect(query).toBeDefined();
})
it('2. Send query and check result', async()=>{
dataReq.requestData(query, 'conversions').then( res => {
expect(res).toContain("panel");
})
})
});
我希望您专注于一部分:DataRequester服务。 这是一种具有返回承诺的方法的服务,并调用后端的特定部分以返回数据。 我只想在这里检查此响应对象是否包含属性“ panel”以及测试...
……实际上说它存在! 但是,如果我尝试将属性的名称更改为某些不存在的属性,它也将验证为true。 因此,也许HTTP请求在这里不能正常工作,在这里做错了。
我在这段代码中做不好吗? 为什么DataRequester的“ requestData”方法不能正确执行,所以Jasmine能够在响应对象中正确测试我想要的条件?
是的,您在代码中占了上风。但是不用担心,刚开始时我也做过同样的事情。
首先,你必须了解单元测试的基础知识:单元测试旨在防止在一个单位 的副作用 。
副作用是所需行为的变化:例如,您要使div的颜色为蓝色,并且在进行一些代码编辑后,将其着色为红色:这是一个副作用。
单位是您要测试的功能。 在Angular中,您可以看到以下内容:
describe('AppComponent'
在这里,您正在测试AppComponent
。
现在,我们解决了这一点,让我们回顾一下测试中的错误:您使用服务的真实实例 。 这意味着您不再没有一个单元:您正在测试多个单元。
您必须嘲笑您的服务。 您将检查组件是否实际上在调用服务,而不是服务是否在调用API(这将由服务本身的单元测试进行检查)。
在您的测试床上:
TestBed.configureTestingModule({
declarations: [
MainComponent,
Menu,
MessageViewer
],
imports: [
BrowserModule,
BrowserAnimationsModule,
routing,
AngularFontAwesomeModule,
FormsModule,
HttpModule,
ChartModule,
Ng4LoadingSpinnerModule.forRoot(),
NgbModule.forRoot()
],
providers: [
{
provide: ReactiveService,
useValue : {}
},
{
provide: DataRequester,
useValue: {}
},
{ provide: APP_BASE_HREF, useValue : '/' }
]
通常,组件仅处理视图:您实际上并不能模拟它们(尽管您应该 )。
这允许您删除HttpModule
,这在任何测试中都是不需要的。
您还可以删除路由模块,因为Angular已经提供了它的模拟: RouterTestingModule
。
你的测试床变成这个
TestBed.configureTestingModule({
declarations: [
MainComponent,
Menu,
MessageViewer
],
imports: [
BrowserModule,
BrowserAnimationsModule,
RouterTestingModule,
AngularFontAwesomeModule,
FormsModule,
ChartModule,
Ng4LoadingSpinnerModule.forRoot(),
NgbModule.forRoot()
],
providers: [
{
provide: ReactiveService,
useValue : {}
},
{
provide: DataRequester,
useValue: {}
},
{ provide: APP_BASE_HREF, useValue : '/' }
]
现在,您已经有了合适的测试床。
您所要做的就是,在useValue
中添加useValue
, 并使用正确的签名在组件中使用的每个服务属性 。
例如,假设您的应用程序组件具有以下内容:
ngOnInit() {
this.dataRequester.requestWidth('URL').subscribe(res => this.reactiveService.width = res);
}
然后,您的测试台将变为:
TestBed.configureTestingModule({
declarations: [
MainComponent,
Menu,
MessageViewer
],
imports: [
BrowserModule,
BrowserAnimationsModule,
RouterTestingModule,
AngularFontAwesomeModule,
FormsModule,
ChartModule,
Ng4LoadingSpinnerModule.forRoot(),
NgbModule.forRoot()
],
providers: [
{
provide: ReactiveService,
useValue : {
width: 0
}
},
{
provide: DataRequester,
useValue: {
requestWidth: () => of(100)
}
},
{ provide: APP_BASE_HREF, useValue : '/' }
]
(模拟的值并不重要,您可以根据需要更改它们)
如您所见,由于您的请求者服务返回了一个Observable,因此您也不得不返回一个。 并且由于您的反应式服务存储了宽度,因此您必须声明一个类型为number的变量。
现在,在测试中,使用前面的示例,您将执行以下操作:
it(`should get width from requester and store it in reactive service`, fakeAsync(() => {
spyOn(component['dataRequester'], 'requestWidth').and.callThrough();
component.ngOnInit();
tick();
expect(component['dataRequester'].requestWidth).toHaveBeenCalledWith('URL');
expect(component['reactiveService'].width).toEqual(100);
}));
您声明所做的事情(测试驱动),监视服务(以查看是否已被调用),然后进行调用(因为我们的模拟已经是一个Observable并返回100)。
然后,调用该方法进行测试,然后刷新异步调用( fakeAsync
和tick
是Angular的一部分,您可以在有关测试的文档中找到它们)。
最后,您会做出期望。
这样,您就成功地测试了第一种方法!
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.