如何为CombineTest rxjs编写Jasmine单元测试用例

如何为CombineTest rxjs编写Jasmine单元测试用例,rxjs,angular2-services,angular2-observables,combinelatest,Rxjs,Angular2 Services,Angular2 Observables,Combinelatest,mycomponent.ts import { Component, OnInit } from '@angular/core'; import {FormGroup,FormControl} from '@angular/forms' import { DataServiceService } from './data-service.service'; import {combineLatest,Observable,pipe} from 'rxjs'; import {map,tap} f

mycomponent.ts

import { Component, OnInit } from '@angular/core';
import {FormGroup,FormControl} from '@angular/forms'
import { DataServiceService } from './data-service.service';
import {combineLatest,Observable,pipe} from 'rxjs';
import {map,tap} from 'rxjs/operators';
import {Model} from './mode';
@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: [ './app.component.css' ]
})
export class AppComponent  {

  constructor(private dataService: DataServiceService){}
  name = 'Angular';
  myForm: FormGroup;
  observableResult$: Observable<any>;

  ngOnInit(){
    this.myForm = new FormGroup({
      localId: new FormControl()
    })

  this.observableResult$ = combineLatest(
    this.myForm.get('localId').valueChanges,
    this.dataService.getDataFromURL(),
    (localIdSelected, dataFromAPI) => ({localIdSelected,dataFromAPI})).
    pipe(map(each => this.filterData(each.dataFromAPI,each.localIdSelected)));

    this.observableResult$.subscribe(value => {
      debugger
    })

  }
  filterData(dataFromAPI,localIDSelected){
    debugger
     return dataFromAPI.filter(item => item.userId > Number(localIDSelected));
    }

}
import { Injectable } from '@angular/core';
import {HttpClient} from '@angular/common/http'
import {Model} from './mode';
import {Observable} from 'rxjs';
@Injectable()
export class DataServiceService {

  constructor(private http:HttpClient) { }

  getDataFromURL():Observable<Model>{
    return this.http.get<Model>('https://jsonplaceholder.typicode.com/todos');
  }

}
const spyFilter = spyOn(component as any, filterData).and.callThrough();

const constAPIData$ = staticDataServiceMock.getAPIData();
                    spyOn(staticDataServiceMock, 'getAPIData').and.returnValue(
                        observableOf(countryStaticData$)
                    );
component.myForm.get('localId').setValue(1);

component.observableResult$.subscribe(value => {
expect(value[0].id==21).toBeTrue();
});
export class StaticDataMock{

static getAPIData(): Observable<StaticDataElements[]> {
    return [
  {
    "userId": 1,
    "id": 1,
    "title": "delectus aut autem",
    "completed": false
  },
  {
    "userId": 1,
    "id": 2,
    "title": "quis ut nam facilis et officia qui",
    "completed": false
  },
  {
    "userId": 1,
    "id": 3,
    "title": "fugiat veniam minus",
    "completed": false
  },
  {
    "userId": 1,
    "id": 4,
    "title": "et porro tempora",
    "completed": true
  }];
  }
}
staticDatamock.ts

import { Component, OnInit } from '@angular/core';
import {FormGroup,FormControl} from '@angular/forms'
import { DataServiceService } from './data-service.service';
import {combineLatest,Observable,pipe} from 'rxjs';
import {map,tap} from 'rxjs/operators';
import {Model} from './mode';
@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: [ './app.component.css' ]
})
export class AppComponent  {

  constructor(private dataService: DataServiceService){}
  name = 'Angular';
  myForm: FormGroup;
  observableResult$: Observable<any>;

  ngOnInit(){
    this.myForm = new FormGroup({
      localId: new FormControl()
    })

  this.observableResult$ = combineLatest(
    this.myForm.get('localId').valueChanges,
    this.dataService.getDataFromURL(),
    (localIdSelected, dataFromAPI) => ({localIdSelected,dataFromAPI})).
    pipe(map(each => this.filterData(each.dataFromAPI,each.localIdSelected)));

    this.observableResult$.subscribe(value => {
      debugger
    })

  }
  filterData(dataFromAPI,localIDSelected){
    debugger
     return dataFromAPI.filter(item => item.userId > Number(localIDSelected));
    }

}
import { Injectable } from '@angular/core';
import {HttpClient} from '@angular/common/http'
import {Model} from './mode';
import {Observable} from 'rxjs';
@Injectable()
export class DataServiceService {

  constructor(private http:HttpClient) { }

  getDataFromURL():Observable<Model>{
    return this.http.get<Model>('https://jsonplaceholder.typicode.com/todos');
  }

}
const spyFilter = spyOn(component as any, filterData).and.callThrough();

const constAPIData$ = staticDataServiceMock.getAPIData();
                    spyOn(staticDataServiceMock, 'getAPIData').and.returnValue(
                        observableOf(countryStaticData$)
                    );
component.myForm.get('localId').setValue(1);

component.observableResult$.subscribe(value => {
expect(value[0].id==21).toBeTrue();
});
export class StaticDataMock{

static getAPIData(): Observable<StaticDataElements[]> {
    return [
  {
    "userId": 1,
    "id": 1,
    "title": "delectus aut autem",
    "completed": false
  },
  {
    "userId": 1,
    "id": 2,
    "title": "quis ut nam facilis et officia qui",
    "completed": false
  },
  {
    "userId": 1,
    "id": 3,
    "title": "fugiat veniam minus",
    "completed": false
  },
  {
    "userId": 1,
    "id": 4,
    "title": "et porro tempora",
    "completed": true
  }];
  }
}
导出类StaticDataMock{
静态getAPIData():可观察{
返回[
{
“用户ID”:1,
“id”:1,
“标题”:“授权或授权”,
“已完成”:false
},
{
“用户ID”:1,
“id”:2,
“标题”为“我的脸和办公室”,
“已完成”:false
},
{
“用户ID”:1,
“id”:3,
“标题”:“福吉亚威尼斯小号”,
“已完成”:false
},
{
“用户ID”:1,
“id”:4,
“标题”:“临时工”,
“已完成”:真
}];
}
}

我已经添加了我的测试用例来覆盖app.spec.ts中的CombineTest操作符和filterData,但是所需的代码失败了。我希望调用filterData失败了。CombineTest将触发valueChange事件并从API获取数据。我可以在spec文件中创建mock和setValue,但它仍然不起作用。

好的,为了尝试帮助您进行这项工作,我使用您迄今为止提供的数据设置了一个Stackblitz。这是你的电话号码

我做了一些事情来让测试正常进行

  • 我将
    StaticDataMock
    类中的
    getAPIData()
    方法类型更改为public,以便您可以从类外部调用它
  • 我让方法返回()的
    ,将返回值转换为数据的可观察值
  • 我猜你实现了DataServiceService模拟,详情见Stackblitz
  • 我创建了一个Jasmine spyObject来拦截服务中对
    getDataFromURL()
    的调用,并返回您使用
    StaticDataMock
    创建的可观察对象
  • 我重新安排了规范中调用的顺序,并执行了
    console.log()
    以显示
    组件.observeResult$
    从不发出

更新 根据下面的评论,上面的Stackblitz链接已经更新,目前正在运行。Stackblitz的工作规范如下:

it('should change return of service.function1() only', () => {
    fixture.detectChanges(); 
    component.observableResult$.subscribe(value => {
        console.log('observable Emitted, value is ', value);
        expect(value[0].id==1).toBe(true); 
    });
    component.myForm.get('localId').setValue(1);
});
关键是首先设置subscribe,然后在表单中发出一个新值,该值将更新
combinelatetest()
并在
subscribe()
中执行代码


我很高兴这能奏效

你的问题是什么?如果您希望有人帮助您编写测试用例,那么您需要非常清楚您到底要测试什么。您还需要显示更多的细节,例如,
mock.getIds()
是什么以及它返回什么,如果您已经设置了其他mock及其实现,测试床的细节(如果您正在使用),等等。@dmcgrandle:我已经更新了我的问题,请检查谢谢,我们正在接近。)我对各种文件的名称有点困惑。
app.component.html
mycomponent.ts
的模板吗?文件
mycomponent.spec.ts
在哪里?另外,请展示整个设置和测试台实现-事实上,除了正在工作的规范之外,还有整个规范文件,您不需要帮助。您显示了
StaticDataMock
类,但在您调用的规范中,
staticDataServiceMock
——但没有显示这两个类之间的关系(甚至没有显示它们之间的关系)(我猜是您将其注入到TestBed[providers]数组中…),感谢您的努力!!!在调试过程中,我尝试了你的代码,但没想到我得到了未定义的订阅值。是的,这就是我在上面的讨论中所说的,在测试你的编码方式时,很难掌握可观测值。它可能需要重构,但只有你知道这段代码实际要实现什么-从你发布的内容到目前为止我还不清楚。我试图使用CombineTest()正确地链接观察值,我有两个控件,一个用于国家,另一个用于州,当国家更改第一个控件时(combineLatest的第一个参数),它应该触发combineLatest并从国家/地区服务获取相应的状态(combineLatest的第二个参数)。第二个参数的结果是conatins对象数组,然后我必须使用所选国家/地区(使用所选国家/地区-combineLatest的第一个参数)对其进行管道传输并过滤状态这与您提供的链接几乎相同,无法到达测试用例中的expect块。只需将
component.myForm.get('localId').setValue(1);
移动到订阅之后,它就可以工作了。需要异步思考-一旦订阅被设置,我们就可以使用
setValue(1)触发新的发射
,这将导致执行订阅。:)