是否可以验证 Angular 组件内的服务调用?

mal*_*dao 3 unit-testing jasmine karma-jasmine angular

我在尝试验证 Angular 5 组件函数中的服务调用时遇到了许多问题。

@Component({
    selector: 'app-example',
    templateUrl: './app-example.html',
    styleUrls: ['./app-example.css'],
    providers: [ PersistanceService, AnotherService ]
})
export class ExampleComponent {

    callPersist: boolean = false;

    private simpleObj = {
        "name": "a",
        "age" : 20
    }

    constructor(private persistanceService: PersistanceService, anotherService: AnotherService) {}

    persist() {
        if (this.callPersist)
            this.persistanceService.persist(this.simpleObj);
        else
            this.anotherService.terminate();
    }
}
Run Code Online (Sandbox Code Playgroud)

在我的测试中,我想验证在调用persist() 时,是否正在调用相应的服务。这是我的测试用例:

it('should call persistService', () => {

    let persistService = TestBed.get(PersistanceService); //this is being declared in TestBed.configureTestingModule

    spyOn(persistService, 'persist').and.callThrough(); //create spy

    component.callPersist = true; //set flag for persistance
    fixture.detectChanges(); //update variables in fixture

    component.persist(); //call parent method

    expect(persistService.persist).toHaveBeenCalled(); // error
    expect(persistService).toHaveBeenCalled(); // error
    expect(persistService.calls.any()).toBeTruthy(); //error
});
Run Code Online (Sandbox Code Playgroud)

不管期待如何,结果永远是

预期的间谍一直被调用。

满足期望的唯一情况是当我直接在我的测试用例中调用间谍时。然而,这对我来说毫无用处。我希望像 Mockito 一样使用.verify()来验证我的服务调用

有没有可能我完全错了?

PS:测试是通过 Jasmine 2.8.0 运行的

编辑:添加 beforeEach() 方法

beforeEach(async() => {
    TestBed.configureTestingModule({
        declarations: [ ExampleComponent ],
        providers: [
            PersistanceService,
            AnotherService
        ]
    }).compileComponents();

    fixture = TestBed.createComponent(ExampleComponent);
    component = fixture.componentInstance;

    fixture.detectChanges();
});
Run Code Online (Sandbox Code Playgroud)

yur*_*zui 8

让我们看看您要测试什么。

您拥有在组件级别提供服务的组件:

@Component({
    ...
    providers: [ PersistanceService, AnotherService ]
})
export class ExampleComponent {
Run Code Online (Sandbox Code Playgroud)

然后在您的测试中,您在根模块级别提供相同的服务:

TestBed.configureTestingModule({
    declarations: [ ExampleComponent ],
    providers: [
        PersistanceService,
        AnotherService
    ]
}).compileComponents();
Run Code Online (Sandbox Code Playgroud)

您可以猜到,当测试运行时,这些服务将是完全不同的实例。

如何检查?

const componentPersistService = fixture.debugElement.injector.get(PersistanceService);
const globalPersistService = TestBed.get(PersistanceService);

componentPersistService === globalPersistService // false
Run Code Online (Sandbox Code Playgroud)

另请参阅文档:

我想你现在明白我们需要测试在组件级别提供的服务。

干得好:

it('should call persistService', () => {
   const persistService = fixture.debugElement.injector.get(PersistanceService);

   const persistSpy = spyOn(persistService, 'persist').and.callThrough(); // create spy

   component.callPersist = true; // set flag for persistance
   fixture.detectChanges(); // update variables in fixture

   component.persist(); // call parent method

   expect(persistService.persist).toHaveBeenCalled(); // error
   expect(persistSpy).toHaveBeenCalled(); // error
   expect(persistSpy.calls.any()).toBeTruthy(); // error
});
Run Code Online (Sandbox Code Playgroud)

注意:如果你想提供组件级服务的自定义实现,那么你应该使用overrideComponent方法,例如:

fixture = TestBed.overrideComponent(ExampleComponent, {
  providers: { provide: PersistanceService, useClass: PersistanceServiceSpy }
})
.createComponent(ExampleComponent);
Run Code Online (Sandbox Code Playgroud)