当在组件的根目录中提供服务时如何监视服务方法
How to spy on methods of service when the service is provided in the root of Component
我正在使用 karma-jasmine 为 angular 组件编写单元测试。我在我的 ProfileComponent 中使用了提供程序并注入了 ProfileService。
profile.component.ts
@Component({
selector: 'app-profile',
templateUrl: './profile.component.html',
styleUrls: ['./profile.component.scss'],
providers: [ProfileService]
})
export class ProfileComponent implements OnInit {
public data;
constructor(private profileService: ProfileService) {}
ngOnInit() {
await this.profileService.login();
this.profileService.getData('A').subscribe((result) => {
this.data = result;
});
}
}
profile.service.ts
@Injectable()
export class ProfileService {
private baseUrl: string;
constructor(private http: HttpClient) {
this.baseUrl = 'https://localhost:4002';
}
public async login() {
const loginUrl = `${this.baseUrl}/api/Login`;
return this.http.post(loginUrl, {}, { headers }).toPromise();
}
getData(id: string) {
const url = `${this.baseUrl}/api/GetData/${id}`;
return this.http.get(url, { headers });
}
}
profile.component.spec.ts
const data = ['A', 'B', 'C'];
describe('Client.App.ProfileComponent', () => {
let component: ProfileComponent;
let fixture: ComponentFixture < ProfileComponent > ;
let profileService: ProfileService;
let profileData;
beforeEach(async (() => {
TestBed.configureTestingModule({
imports: [HttpClientTestingModule, ReactiveFormsModule, RouterTestingModule],
declarations: [ProfileComponent],
providers: [ProfileService],
schemas: [NO_ERRORS_SCHEMA]
}).compileComponents();
}));
beforeEach(fakeAsync(() => {
profileData = new Subject();
profileService = TestBed.inject < ProfileService > (ProfileService);
spyOn(profileService, 'login').and.returnValue({});
spyOn(profileService, 'getData').and.returnValue(profileData);
fixture = TestBed.createComponent(ProfileComponent);
component = fixture.componentInstance;
fixture.detectChanges();
}));
it('shall create the component', () => {
profileData.next(data);
fixture.detectChanges();
expect(component).toBeDefined();
});
});
我添加了一个调试器并检查它是否登录失败。所以,我有两个问题:
- 因为我在
Profile Component
中使用了提供程序,我可以在 profile.component.spec.ts
文件中注入 ProfileService
吗,因为它会创建同一服务的两个实例?
- 如何监视 ProfileService 的 login() 和 getData() 如下语句不起作用...?
spyOn(profileService, 'login').and.returnValue({});
请帮我解决这个问题。
1.) 我认为你有什么很好,将 ProfileService
放在 TestBed.configureTestingModule
的 provider
数组中是好的,当组件被创建时,它知道如何制作它。每次创建组件时,它都将是一个单独的提供者,但无论是在组件中还是在全局范围内提供提供者,都会出现这种情况,因为测试会构造和析构 (beforeEach.... TestBed.configureTestingModule...) .
2.) 试试`spyOn(profileService, 'login').and.returnValue(Promise.resolve({}));
旁注:ngOnInit
需要异步装饰器才能使用 await。
首先你需要提供一个模拟而不是提供实际的服务实例。之后,您需要提供该服务方法的伪造实现。请在下面找到所需的更改和内联评论。
const data =['A','B','C'];
describe('Client.App.ProfileComponent', () => {
let component: ProfileComponent;
let fixture: ComponentFixture<ProfileComponent>;
let profileService: jasmine.SpyObj<ProfileService>;
beforeEach(async(() => {
// create a spied service and use it inside providers array
profileService = jasmine.createSpyObj('ProfileService', ['login', 'getData']);
TestBed.configureTestingModule({
imports: [HttpClientTestingModule, ReactiveFormsModule, RouterTestingModule],
declarations: [ProfileComponent],
providers: [ { provide: ProfileService, useValue: profileService ],
schemas: [NO_ERRORS_SCHEMA]
}).compileComponents();
// provide fake implementation to service methods
profileService.login.and.returnValue(Promise.resolve('success'));
profileService.getData.and.returnValue(of(data)); // of is rxjs operators- import
fixture = TestBed.createComponent(ProfileComponent);
component = fixture.componentInstance;
fixture.detectChanges();
}));
it('shall create the component', () => {
expect(component).toBeDefined();
});
});
- 因为我在 Profile 组件中使用了提供程序,我可以在 profile.component.spec.ts 文件中注入 Profileervice,因为它将创建同一服务的两个实例..??
答案:您应该为该服务创建一个 Stub
,以使用 useClass
替换对实际 ProfileService
的依赖
export class ProfileServiceStub {
getData(id: string) {
return of({some_obj: "value"})
}
}
和在spec.ts
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [HttpClientTestingModule, ReactiveFormsModule, RouterTestingModule],
declarations: [ProfileComponent],
providers: [ {provide: ProfileService , useClass: ProfileServiceStub } ], // <-- useclass here
schemas: [NO_ERRORS_SCHEMA]
}).compileComponents();
- 如何监视 ProfileService 的 login() 和 getData() 如下语句不起作用...?
答:在组件构造函数中创建服务public
如下:
constructor(public profileService: ProfileService) { }
强烈推荐你阅读my article on something similar where I have tested the component
我正在使用 karma-jasmine 为 angular 组件编写单元测试。我在我的 ProfileComponent 中使用了提供程序并注入了 ProfileService。
profile.component.ts
@Component({
selector: 'app-profile',
templateUrl: './profile.component.html',
styleUrls: ['./profile.component.scss'],
providers: [ProfileService]
})
export class ProfileComponent implements OnInit {
public data;
constructor(private profileService: ProfileService) {}
ngOnInit() {
await this.profileService.login();
this.profileService.getData('A').subscribe((result) => {
this.data = result;
});
}
}
profile.service.ts
@Injectable()
export class ProfileService {
private baseUrl: string;
constructor(private http: HttpClient) {
this.baseUrl = 'https://localhost:4002';
}
public async login() {
const loginUrl = `${this.baseUrl}/api/Login`;
return this.http.post(loginUrl, {}, { headers }).toPromise();
}
getData(id: string) {
const url = `${this.baseUrl}/api/GetData/${id}`;
return this.http.get(url, { headers });
}
}
profile.component.spec.ts
const data = ['A', 'B', 'C'];
describe('Client.App.ProfileComponent', () => {
let component: ProfileComponent;
let fixture: ComponentFixture < ProfileComponent > ;
let profileService: ProfileService;
let profileData;
beforeEach(async (() => {
TestBed.configureTestingModule({
imports: [HttpClientTestingModule, ReactiveFormsModule, RouterTestingModule],
declarations: [ProfileComponent],
providers: [ProfileService],
schemas: [NO_ERRORS_SCHEMA]
}).compileComponents();
}));
beforeEach(fakeAsync(() => {
profileData = new Subject();
profileService = TestBed.inject < ProfileService > (ProfileService);
spyOn(profileService, 'login').and.returnValue({});
spyOn(profileService, 'getData').and.returnValue(profileData);
fixture = TestBed.createComponent(ProfileComponent);
component = fixture.componentInstance;
fixture.detectChanges();
}));
it('shall create the component', () => {
profileData.next(data);
fixture.detectChanges();
expect(component).toBeDefined();
});
});
我添加了一个调试器并检查它是否登录失败。所以,我有两个问题:
- 因为我在
Profile Component
中使用了提供程序,我可以在profile.component.spec.ts
文件中注入ProfileService
吗,因为它会创建同一服务的两个实例? - 如何监视 ProfileService 的 login() 和 getData() 如下语句不起作用...?
spyOn(profileService, 'login').and.returnValue({});
请帮我解决这个问题。
1.) 我认为你有什么很好,将 ProfileService
放在 TestBed.configureTestingModule
的 provider
数组中是好的,当组件被创建时,它知道如何制作它。每次创建组件时,它都将是一个单独的提供者,但无论是在组件中还是在全局范围内提供提供者,都会出现这种情况,因为测试会构造和析构 (beforeEach.... TestBed.configureTestingModule...) .
2.) 试试`spyOn(profileService, 'login').and.returnValue(Promise.resolve({}));
旁注:ngOnInit
需要异步装饰器才能使用 await。
首先你需要提供一个模拟而不是提供实际的服务实例。之后,您需要提供该服务方法的伪造实现。请在下面找到所需的更改和内联评论。
const data =['A','B','C'];
describe('Client.App.ProfileComponent', () => {
let component: ProfileComponent;
let fixture: ComponentFixture<ProfileComponent>;
let profileService: jasmine.SpyObj<ProfileService>;
beforeEach(async(() => {
// create a spied service and use it inside providers array
profileService = jasmine.createSpyObj('ProfileService', ['login', 'getData']);
TestBed.configureTestingModule({
imports: [HttpClientTestingModule, ReactiveFormsModule, RouterTestingModule],
declarations: [ProfileComponent],
providers: [ { provide: ProfileService, useValue: profileService ],
schemas: [NO_ERRORS_SCHEMA]
}).compileComponents();
// provide fake implementation to service methods
profileService.login.and.returnValue(Promise.resolve('success'));
profileService.getData.and.returnValue(of(data)); // of is rxjs operators- import
fixture = TestBed.createComponent(ProfileComponent);
component = fixture.componentInstance;
fixture.detectChanges();
}));
it('shall create the component', () => {
expect(component).toBeDefined();
});
});
- 因为我在 Profile 组件中使用了提供程序,我可以在 profile.component.spec.ts 文件中注入 Profileervice,因为它将创建同一服务的两个实例..??
答案:您应该为该服务创建一个 Stub
,以使用 useClass
ProfileService
的依赖
export class ProfileServiceStub {
getData(id: string) {
return of({some_obj: "value"})
}
}
和在spec.ts
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [HttpClientTestingModule, ReactiveFormsModule, RouterTestingModule],
declarations: [ProfileComponent],
providers: [ {provide: ProfileService , useClass: ProfileServiceStub } ], // <-- useclass here
schemas: [NO_ERRORS_SCHEMA]
}).compileComponents();
- 如何监视 ProfileService 的 login() 和 getData() 如下语句不起作用...?
答:在组件构造函数中创建服务public
如下:
constructor(public profileService: ProfileService) { }
强烈推荐你阅读my article on something similar where I have tested the component