TestBed.get 和 new Service(...dependencies) 有啥区别

Posted

技术标签:

【中文标题】TestBed.get 和 new Service(...dependencies) 有啥区别【英文标题】:What's the difference between TestBed.get and new Service(...dependencies)TestBed.get 和 new Service(...dependencies) 有什么区别 【发布时间】:2019-11-08 14:26:41 【问题描述】:

angular guide 演示了两种不同的测试方式,一种是调用 new Service() 并直接向构造函数提供依赖项,另一种是通过调用 TestBed.get(Service) 使用依赖注入。

这两者在功能上似乎与我相同,除了当我连续调用 TestBed.get() 时,它不会在第一次调用后调用构造函数。

angular documentation 还提到 TestBed.get() 已被弃用(即使指南仍然引用它!),我应该改用 Type 或 InjectionToken,但我看不出其中任何一个如何类可以替换 TestBed.get()。

【问题讨论】:

【参考方案1】:

当你调用TestBed.configureTestingModule( providers: [SomeService] ); 时,这会设置一个 NgModule,可以在后续测试中使用。如果您调用TestBed.get(SomeService),这将从注入器中检索SomeService,并在需要时将其实例化。如果它被实例化,那么注入器会注入对其依赖项的引用并返回一个新的服务实例。

如果 SomeService 已经被实例化,就像你的情况一样,那么 TestBed 不需要创建它。这意味着它不会在以后调用构造函数。

要回答您关于差异的问题,如果您要模拟所有依赖项并且不需要访问 DOM,则它们基本上是相同的。在没有 TestBed 的情况下实例化类要快得多,因为没有为每个测试加载依赖注入器的开销。

至于不推荐使用的 TestBed.get(),在 Angular 8.0.0 中,仅不推荐使用允许任何类型的特定重载(请参阅https://github.com/angular/angular/blob/master/packages/core/testing/src/test_bed.ts#L67)。而不是get(token: any, notFoundValue?: any): any;,签名改为get<T>(token: Type<T> | InjectionToken<T>, notFoundValue?: T, flags?: InjectFlags): any;,这意味着您必须使用类引用或注入令牌。没有字符串或其他东西可以引用注入器中的东西。

在 Angular 9.0.0 中,TestBed.get() 方法将被完全弃用,您需要改用 TestBed.inject。见https://github.com/angular/angular/blob/master/packages/core/testing/src/test_bed.ts#L65

【讨论】:

【参考方案2】:

Deprecated from v9.0.0 use TestBed.inject

get(token: any, notFoundValue?: any): any

看看我们现在如何注入:

describe('MyAmountComponent', () => 
  let component: MyAmountComponent;
  let fixture: ComponentFixture<MyAmountComponent>;
  let productService: ProductService;
  let orderService: OrderService;
  beforeEach(() => 
    TestBed.configureTestingModule(
       .....
    )
    .compileComponents();
    productService = TestBed.inject(ProductService);
    orderService = TestBed.inject(OrderService);
  );

添加so可能会对某人有所帮助。

【讨论】:

【参考方案3】:

get 已弃用:从 v9.0.0 开始使用 TestBed.inject(弃用)

let valueServiceSpy: jasmine.SpyObj<ValueService>;

beforeEach(() => 
  const spy = jasmine.createSpyObj('ValueService', ['getValue']);

  TestBed.configureTestingModule(
    providers: [
       provide: ValueService, useValue: spy 
    ]
  );
  // This is new way to inject Spied Service
  valueServiceSpy = TestBed.inject(ValueService) as jasmine.SpyObj<ValueService>; 
);

然后在测试中

it('#getValue should return stubbed value from a spy', () => 
  valueServiceSpy.getValue.and.returnValue(yourValue);
  ...
);

官方文档:https://v9.angular.io/guide/testing#angular-testbed

【讨论】:

以上是关于TestBed.get 和 new Service(...dependencies) 有啥区别的主要内容,如果未能解决你的问题,请参考以下文章

在docker中启动服务报错:New main PID 558 does not belong to service

Travel GuideCZ's New Non-Stop Service from LA to Shenyang

Service系列:Service创建和生命周期

Activity如何与Service通信?

Nginx返回位置

android 的Service里面多次启动一个Activity只能用FLAG_ACTIVITY_NEW_TASK,那么怎么才能只启动一次呢?