[英]How to test Angular 6 service with dependency that uses private methods/properties to modify output of public methods/properties
我坚持尝试在 Angular 6 应用程序中为依赖于另一个服务的服务编写 Jasmine/Karma 测试,并且该依赖项有几个私有属性/方法可以修改公共方法的执行方式,而我的测试总是失败。
所有代码在运行时都按预期工作,但我不知道如何正确测试它。 我已经尝试过对不起作用的私有方法和属性进行间谍活动,也没有将它们更改为公共。 显然我错过了一些东西。
现在,我不在乎或想要测试DependencyService
。 I want to be able to test MyService
function doSomething
works, currently it always returns null
so my test output is Failed: Cannot read property 'subscribe' of null
. 删除postData()
中的if
语句会按预期返回 observable 并且测试通过。
感觉我在这里监视了错误的事情,因为我的测试与依赖服务或localStorage
值紧密耦合。
如何在我的服务依赖项中模拟/监视checkAuth
和isAuth
? 也许更准确地说,我如何正确测试doSomething()
以便将测试隔离到MyService
服务?
export class MyService {
constructor(private depService: DependencyService) { }
public doSomething(additionalPayload: Object) {
const payload = { ...additionalPayload, modified: true };
return this.depService.postData('/api/endpoint', payload);
}
}
export class DependencyService {
constructor(private httpClient: HttpClient) { }
private isAuth: boolean = false;
private checkAuth() {
const token = localStorage.get('token');
if (token !== null) {
this.isAuth = true;
} else {
this.isAuth = false;
}
}
postData(url, body): Observable<any> {
this.checkAuth();
if (!this.isAuth) {
return null;
}
return this.httpClient.post(url, body);
}
}
到目前为止没有通过的myservice.spec.ts
:
describe('MyService', () => {
let httpTestingController: HttpTestingController;
let myService: MyService;
let dependencyServiceSpy: jasmine.SpyObj<DependencyService>;
beforeEach(() => {
const dependencyServiceSpyObj = jasmine.createSpyObj('DependencyService', ['postData']);
TestBed.configureTestingModule({
imports: [ HttpClientTestingModule ],
providers: [
MyService,
{ provide: DependencyService, useValue: dependencyServiceSpyObj },
]
});
httpTestingController = TestBed.get(HttpTestingController);
myService = TestBed.get(MyService);
dependencyServiceSpy = TestBed.get(DependencyService);
});
afterEach(() => {
httpTestingController.verify();
});
it('#doSomething should post some data', async(() => {
const payloadData: Object = {
name: 'Ash',
food: 'donut'
};
const responseData: Object = {
success: true,
msg: 'Payload received'
};
// HELP HERE ↓
// need to spy/mock dependencyService.isAuth so that it is `true`
// otherwise inside `postData` the if statement will always return a `null` value
// ...spy/mock `localStorage`?
dependencyServiceSpy.postData.and.returnValue(/* return http observable so that .subscribe can be called */);
myService.doSomething(payloadData).subscribe(data => {
expect(data).toEqual(responseData);
}, fail);
const req = httpTestingController.expectOne('/api/endpoint');
expect(req.request.method).toEqual('POST');
expect(req.request.body).toEqual({ ...payloadData, modified: true });
expect(dependencyServiceSpy.postData.calls.count()).toBe(1);
expect(dependencyServiceSpy.postData.calls.mostRecent().returnValue).toBe(responseData);
req.flush(responseData);
}));
});
您不必担心依赖服务。 如果用户通过了身份验证,或者网络调用是否正确,应该是依赖服务规范的一部分。
您监视dependencyService
的方式也存在问题。 TestBed.get(DependencyService)
返回DependencyService
的当前实例,而不是间谍。 将变量重命名如下是明智的:
let dependencyService: DependencyService;
和分配如下:
dependencyService = TestBed.get(DependencyService);
你只需要监视postData
方法。
从MyService
的角度来看, DependencyService
只有两种场景。
用户未通过身份验证
在这种情况下,您只需要postData
应该返回 null。 您不必担心checkAuth
。 您可以监视postData
并返回带有 null 值的 Observable。 您只关心postData
方法的output,而不关心output是如何生成的。
it('#doSomething should return null if user is not authenticated', () => { const payloadData = { name: 'Ash', food: 'donut' }; spyOn(dependencyService, 'postData').and.returnValue(Observable.create(observer => { observer.next(null); observer.complete(); })); myService.doSomething('/api/endpoint', payloadData).subscribe(data => { expect(data).toBeNull(); }, fail); });
正如您在上面看到的,您无需指定postData
如何返回 null。 您知道在这种情况下postData
应该返回 null。 它是如何实现的需要在DependencyService
的规范中进行测试。
用户已通过身份验证
在这种情况下, postData
从 HTTP 调用返回值。 同样,您只需要返回值。 网络调用是否正确将在DependencyService
的规范中进行测试。
it('#doSomething should post some data', () => { const payloadData = { name: 'Ash', food: 'donut' }; const responseData = { success: true, msg: 'Payload received' }; spyOn(dependencyService, 'postData').and.returnValue(Observable.create(observer => { observer.next(responseData); observer.complete(); })); myService.doSomething('/api/endpoint', payloadData).subscribe(data => { expect(data).toEqual(responseData); }, fail); });
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.