如何在angular中模拟服务类的属性(Jasmine/Karma)

如何在angular中模拟服务类的属性(Jasmine/Karma),angular,jasmine,angular6,karma-jasmine,spy,Angular,Jasmine,Angular6,Karma Jasmine,Spy,我试图从我的服务中模拟currentOrganizationMessageSource,但出现以下错误: this.OrganizationService.currentOrganizationMessageSource.subscribe不是函数 我尝试使用spyOnProperty,但得到的结果是currentOrganizationMessageSource不是属性 类别: export class OrganizationEditComponent implements OnInit {

我试图从我的服务中模拟currentOrganizationMessageSource,但出现以下错误:

this.OrganizationService.currentOrganizationMessageSource.subscribe不是函数

我尝试使用spyOnProperty,但得到的结果是currentOrganizationMessageSource不是属性

类别:

export class OrganizationEditComponent implements OnInit {

  feedback: any = {};
  appOrgs: OrganizationDataModel;
  organizationLocationTableTitle: string;


  constructor(
    public route: ActivatedRoute,
    private router: Router,
    private orgService: OrganizationService) {
  }


  ngOnInit() {
    this.loadOrganisation();
  }

  private loadOrganisation()
  {
    this.orgService.currentOrganizationMessageSource.subscribe(
      org => this.appOrgs = org);
      this
      .route
      .params
      .pipe(
        map(p => p.id),
        switchMap(id => {
          if (id === 'new') { return of(this.appOrgs); }
          if (id != null) {
            return this.orgService.findByOrganizationsId(id);
          }
        })
      )
      .subscribe(orgs => {
          this.orgService.changeMessage(orgs);
          this.appOrgs = orgs;
          this.feedback = {};
        },
        err => {
          this.feedback = {type: 'warning', message:'Error'};
        }
      );
  }
服务:

export class OrganizationService {

  private OrganizationMessageSource = new BehaviorSubject( new OrganizationDataModel());
  currentOrganizationMessageSource = this.OrganizationMessageSource.asObservable();


  changeMessage(appOrganization: appOrganizationDataModel) {
    this.appOrganizationMessageSource.next(appOrganization);
  }
}
测试规格类别:

fdescribe('OrganizationEditComponent', () => {
  let component: OrganizationEditComponent;
  let fixture: ComponentFixture<OrganizationEditComponent>;
  let activatedRoutes: any = {};


  beforeEach(async(async () => {
    const OrganizationService: OrganizationService = jasmine.createSpyObj('OrganizationService', ['currentOrganizationMessageSource']);
    await TestBed.configureTestingModule({
      declarations: [ OrganizationEditComponent ],
      providers: [
        { provide: ActivatedRoute, useValue: activatedRoutes },
        { provide: Router, useValue: {url: ''}},
        { provide: OrganizationService, useValue: OrganizationService },
      ],      
      imports: [ FormsModule ] ,
      schemas: [CUSTOM_ELEMENTS_SCHEMA, NO_ERRORS_SCHEMA]
    })
    .compileComponents();
    // component.ngOnInit();
    fixture = TestBed.createComponent(OrganizationEditComponent);
    component = fixture.componentInstance;
    fixture.detectChanges();
  }));

  function givenServicesAreMocked() {
    const spy = TestBed.get(OrganizationService);
    // let mockService = jasmine.createSpyObj(OrganizationService, ['currentOrganizationMessageSource']);
    // mockService.currentOrganizationMessageSource.and.returnValue('');
    // spyOnProperty(OrganizationService, "OrganizationMessageSource").and.returnValue([]);
    // OrganizationService.currentOrganizationMessageSource = () => {
    //   return [];
    // };
  }
});
fddescripe('OrganizationEditComponent',()=>{
let组件:OrganizationEditComponent;
let夹具:组件夹具;
让activatedRoutes:any={};
beforeach(异步(异步()=>{
const OrganizationService:OrganizationService=jasmine.createSpyObj('OrganizationService',['currentOrganizationMessageSource']);
等待TestBed.configureTestingModule({
声明:[OrganizationEditComponent],
供应商:[
{提供:ActivatedRoute,useValue:activatedRoutes},
{提供:路由器,useValue:{url:''}},
{提供:OrganizationService,useValue:OrganizationService},
],      
导入:[FormsModule],
模式:[自定义元素模式,无错误模式]
})
.compileComponents();
//组件。ngOnInit();
fixture=TestBed.createComponent(OrganizationEditComponent);
组件=fixture.componentInstance;
fixture.detectChanges();
}));
函数givenServicesRemocked(){
const spy=TestBed.get(OrganizationService);
//让mockService=jasmine.createSpyObj(OrganizationService,['currentOrganizationMessageSource']);
//mockService.currentOrganizationMessageSource.and.returnValue(“”);
//spyOnProperty(OrganizationService,“OrganizationMessageSource”)。和.returnValue([]);
//OrganizationService.currentOrganizationMessageSource=()=>{
//返回[];
// };
}
});

使用操作员的

import { of } from 'rxjs';
在使用前定义orgService:

 let orgService : KhojiOrganizationService;
将此添加到beforeach:

orgService= TestBed.get(KhojiOrganizationService);
测试用例:

it('should fetch data', () => {
   spyOn(orgService, 'currentkhojiOrganizationMessageSource').and.returnValue(of('test Data'));
   component.ngOnInit();
   expect(component.appOrgs).toEqual('test Data');
});

例如,我在
运算符的
内部传递
字符串。您可以在其中传递
对象
/
对象数组
,并根据您的数据模型更改期望值。

您可以基于

从'ts mockry'导入{Mock,mockry};
接口存根{
[键:字符串]:任意;
}
导出函数createMockService(服务:类型,存根?:存根){
mockry.configure('jasmine');
const mockedFunctions=stubs?stubs:{};
如果(!存根){
for(const key in service.prototype){
mockedFunctions[key]=()=>null;
}
}
返回{
提供:服务,
useValue:Mock.of(mockedFunctions)
};
}
那么你可以这样使用它

beforeach(异步(()=>{
TestBed.configureTestingModule({
导入:[SomeModule,OtherModule],
声明:[SomeComponent,MockComponent(OtherComponent)],
提供者:[createMockService(OrganizationService)]
}).compileComponents();
}));
这与您的问题无关,但请注意MockComponent,它是封装您的karma测试的正确方法,因此只允许对您的组件进行测试,而不使用[CUSTOM_ELEMENTS_SCHEMA,NO_ERRORS_SCHEMA],这是一种不好的做法

下面是一个示例,您需要使用of rxjs操作符模拟返回值

从'rxjs'导入{of};
const RESULT=[{id:1,名称:“test”},{id:2,名称:“toto”}];
beforeach(异步(()=>{
TestBed.configureTestingModule({
导入:[SomeModule,OtherModule],
声明:[SomeComponent,MockComponent(OtherComponent)],
提供者:[createMockService(OrganizationService,{yourMethod:()=>of(RESULTS)}]
}).compileComponents();
}));

你的模拟服务总是很容易用这种方式进行模拟。

你的想法是正确的,但是你不能用
createSpyObj
来模拟属性,而只能用方法

import { of } from 'rxjs';
....
// the 2nd argument is for public methods, not properties
    const OrganizationService: OrganizationService = jasmine.createSpyObj('OrganizationService', ['changeMessage']);
// attach currentOrganizationMesageSource as a property to OrganizationService and mock the value
OrganizationService.currentOrganizationMessageSource = of(/* Mock the value here */);
// keep everything else the same
希望这能奏效


您还需要正确模拟
激活的路由
路由器
。对于路由器,只需将
RouterTestingModule
添加到
imports
数组中即可。它由Angular提供,在测试注入路由器的组件/服务时提供帮助。

尝试
spyOn(component.orgService,'currentkhojiOrganizationMessageSource')。和.returnValue(of({}))
returnValue应该是可见的,注意
,我想您需要在您的constructor@KamranKhatti首先,如果通过公开直接引用component.orgService,那么如果我用模拟值替换component.orgService,我的测试类会说类中不存在orgService(让orgService:any={})比我get currentOrganizationMessageSource()方法不存在实际上此服务KhojiOrganizationService在其构造函数中有另一个服务。因此,当我像这样定义TestBad时,让服务:KhojiOrganizationService=new KhojiOrganizationService(http);和orgService=TestBed.get(服务);然后我得到以下失败的错误:Uncaught(承诺中):错误:StaticInjectorError[[object]]:如下定义:let orgService:KhojiOrganizationService;然后使用
测试床
,如回答中所述。