繁体   English   中英

如何使用私有方法/属性来修改 output 的公共方法/属性的依赖项测试 Angular 6 服务

[英]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值紧密耦合。

如何在我的服务依赖项中模拟/监视checkAuthisAuth 也许更准确地说,我如何正确测试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只有两种场景。

  1. 用户未通过身份验证

    在这种情况下,您只需要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的规范中进行测试。

  2. 用户已通过身份验证

    在这种情况下, 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM