我是否需要在单元测试中取消订阅订阅?

时间:2017-04-09 22:06:13

标签: unit-testing angular jasmine karma-jasmine

如果我有如下测试:

it('should return some observable', async(() => {
  mockBackend.connections.subscribe((mockConnection: MockConnection) => {
    const responseOptions = new ResponseOptions({
      body: JSON.stringify(/* some response */)
    });

    mockConnection.mockRespond(new Response(responseOptions));
  });

  service.getSomeObservable()
    .subscribe(result => {
      expect(result).toBe(/* expected response */);
    });
}));

我是否需要取消订阅afterEachafterAll块中的订阅以避免内存问题?还是会被自动删除?

1 个答案:

答案 0 :(得分:0)

@estus是正确的,您无需退订。

tl; dr;

  • 可观察对象/主题对所有订阅者保留引用,直到完成。
  • 具有活动引用的对象无法标记为垃圾回收。基本JS。
  • Http Observables do 完成,在那时放弃订阅,并将其释放给GC。

  • 在“可观察项/主题”被拆除或完成之前,除非您取消订阅,否则无法进行GC的 订阅。

考虑以下简单的Angular TestBed设置:

describe(`DataService`, () => {
  let service: DataService;
  let httpMock: HttpTestingController;

  beforeEach(() => {
    TestBed.configureTestingModule({
      imports: [HttpClientTestingModule],
      providers: [
        DataService,
      ]
    });

    service = TestBed.get(DataService);
    httpMock = TestBed.get(HttpTestingController);
  });

  it(`should get a response`, () => {
    service.getData().subscribe(response => {
      expect(response).toBeTruthy();
    });
  });

对于通过角度Http发出的HttpClient请求,Observable将完成,并且对GC的对订户的引用也将释放。在如上所示的常规茉莉花角测试中,即使您的Observable尚未完成,DataService所引用的service对象每次beforeEach也会被重置会被调用,并且旧的DataService对象将丢失所有引用,并标记为GC。一旦发生这种情况,DataService中Observable / Subject引用的所有订阅都将丢失对它们的引用,它们也将被GC。

请记住,Observables会发生内存泄漏,因为它们会保留对所有订阅服务器的引用,除非订阅服务器取消订阅。它们将继续对它们及其包含的函数具有有效的引用,并且直到销毁Subject / Observable之前,才能将它们标记为GC。如果主题继续存在,并且您继续添加订阅者(例如同一订阅​​者的新实例),则会继续向内存中添加一堆旧的未使用对象。