我有一个使用模拟服务的组件。我是这样创建的。
注意:对于这个问题,我更改了名称,在项目中它具有更特定的名称。
list.component.spec.ts
describe('ListComponent', () => {
let component: ListComponent;
let fixture: ComponentFixture<ListComponent>;
let ITEMS: ListItem[];
let mockService;
beforeEach(async(() => {
ITEMS = require('../../../../../assets/mockdata/items.json');
mockService = jasmine.createSpyObj(['getItems']);
TestBed.configureTestingModule({
imports: [NoopAnimationsModule, RouterTestingModule, SharedModule],
declarations: [ListComponent, SomePipe, AnotherPipe],
providers: [
{
provide: Service,
useValue: mockService,
},
],
}).compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(TimesheetListComponent);
component = fixture.componentInstance;
mockService.getItems.and.returnValue(of(ITEMS));
fixture.detectChanges();
});
describe('regular behavior', () => {
it('should create', () => {
expect(component).toBeTruthy();
});
list.component.ts
@Component({
selector: 'app-list',
templateUrl: './list.component.html',
styleUrls: ['./list.component.scss'],
})
export class ListComponent implements OnInit {
// left out props;
constructor(private service: Service, private router: Router, private route: ActivatedRoute) {
// This forces the page to reload to the default queryparams when no queryparams are given.
this.router.routeReuseStrategy.shouldReuseRoute = function() {
return false;
};
}
这会出现以下错误:
Error: StaticInjectorError(DynamicTestModule)[Service -> HttpClient]:
StaticInjectorError(Platform: core)[Service -> HttpClient]:
NullInjectorError: No provider for HttpClient!
我也使用此DetailComponent
使用了完全不同的组件(Service
),但它没有任何抱怨。
我不应该提供HttpClient,因为list.component.ts不依赖于该组件,服务具有此依赖关系,因此我分别测试了该代码。
我真的很困惑,也许我在看东西?非常感谢您的帮助。
答案 0 :(得分:1)
在测试实例化子组件的组件时也会出现此问题,该子组件也会使用HttpClient
注入服务。
为说明起见,请考虑以下组件:
@Component({
selector: 'app-parent-component',
template: `<app-child-component></app-child-component>`
})
export class ParentComponent {
constructor(private service: FooService) { }
}
@Component({
selector: 'app-child-component',
})
export class ChildComponent {
constructor(private service: BarService) { }
}
假设FooService
和BarService
都注入了HttpClient
。
根据文档,为ParentComponent
进行的测试可能类似于:
beforeEach(async(() => {
const mockService = jasmine.createSpyObject(['fooMethod']);
TestBed.configureTestingModule({
declarations: [ParentComponent],
providers: [
{
provide: FooService,
useValue: mockService,
},
],
}).compileComponents();
}));
但是,当angular
实例化ParentComponent
时,它也实例化ChildComponent
,这需要注入BarService
。由于您没有告诉TestBed
提供模拟,因此它提供了实际的服务,而服务又取决于HttpClient
。
有许多解决方案。如果要测试ParentComponent
和ChildComponent
的集成,最简单的方法是告诉TestBed
模拟孩子所需的BarService
。如果要维持严格的单元测试,则可以提供一个不向HttpClient
注入TestBed
服务的模拟子组件:
@Component {(
selector: 'app-child-component'
)}
export class MockChildComponent {
constructor() { }
}
并按如下所示设置测试:
TestBed.configureTestingModule({
declarations: [ParentComponent, ChildComponent],
providers: [
{
provide: Service,
useValue: mockService,
},
],
}).compileComponents();
或者您可以通过告诉TestBed
使用CUSTOM_ELEMENTS_SCHEMA
来覆盖组件实例:
TestBed.configureTestingModule({
declarations: [ParentComponent],
providers: [
{
provide: Service,
useValue: mockService,
},
],
schemas: [CUSTOM_ELEMENTS_SCHEMA]
}).compileComponents();