在 Angular 测试中使用模拟服务创建 Class 实例

Create Class Instance with Mock Services in Angular Testing

我在 Angular 9 项目中工作。我创建了一个 class,它是另一个组件中 Material 树的数据源。我实际上只为组件编写了测试,而不是 classes。 我在测试文件中创建此 class 的实例时遇到问题。 我已经制作了模拟服务并将它们添加到测试文件中的 testBed,如下所示:

class MockMyService {
  getData() {...}
}

describe("DynamicDataSource", () => {
  let dynamicDataSource: DynamicDataSource;
  let mockMyService: MockMyService;

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      providers: [
        { provide: MyService, useClass: MockMyService }
      ]
    }).compileComponents();
  }));

  beforeEach(() => {
    mockMyService = TestBed.inject(MyService);
    dynamicDataSource = new DynamicDataSource(null, null);
  });

  it("should create", () => {
    expect(dynamicDataSource).toBeTruthy();
  });
});

在上面我用 dynamicDataSource = new DynamicDataSource(null, null); 创建了 class 的实例但是,为了正确测试 class 中的函数,我需要将属性设置为模拟服务而不是 null。

我想我需要做这样的事情:dynamicDataSource = new DynamicDataSource(null, mockMyService); 但是,尝试这样做会给我一个 Argument of type 'MockMyService' is not assignable to parameter of type 'MyService'. Type 'MockMyService' is missing the following properties from type 'MyService': baseURL, http, logging

的错误

我无法在 MockMyService 中设置这些属性,因为它们是私有属性。 我能够在组件测试中模拟这样的服务,所以我很困惑为什么我必须在这些模拟中拥有这些属性。

是否有更好的方法来测试此 class?如何使用模拟服务在测试中创建它的实例?

任何建议都会很有帮助。

这是 class(顺便说一句):

export class DynamicDataSource implements DataSource<DynamicFlatNode>, OnDestroy {
 dataSubscription: Subscription;

  constructor(
    private _treeControl: FlatTreeControl<DynamicFlatNode>,
    private _database: MyService
  ) {}

  connect(collectionViewer: CollectionViewer): Observable<DynamicFlatNode[]> {...}

  disconnect(collectionViewer: CollectionViewer): void {}

 ...lots of functions and logic...

  ngOnDestroy(): void {
    this.dataSubscription?.unsubscribe();
  }
}

该错误不仅是因为缺少属性,还因为 class MockMyService 不是 class MyService

我以前也遇到过类似的情况。

我认为可能有几种方法可以实现这一点,但我发现最简单的方法可能只是利用 as any 的类型断言。

dynamicDataSource = new DynamicDataSource(null, mockMyService as any)

如果您不 stub/mock MyService 的属性,而 class DynamicDataSource 会 call/use. 但是通过模拟这将使你能够创建间谍来实现我认为你试图测试的东西

class MockMyService {
 getData = jasmine.createSpy('getData'),
 logging = jasmine.createSpy('logging')
 ....

}

注意:在过去的项目中,这被认为有点 hacky,因为在某种程度上覆盖了 TS,但在一些测试覆盖率更重要的地方。