我正在Angular中構建一個小型玩具應用程序,其中包含以下類別(和ProductService
)。該服務包含一個爲產品發出http GET請求的方法。 compnent顯示產品的詳細信息,並使用該服務檢索產品信息。在將HttpModule
添加到應用程序(以及其中的服務)後,我的組件測試失敗,並說「錯誤:沒有提供程序Http!」。Angular:沒有依賴性依賴的提供者
如果我導入HttpModule
,測試再次通過。然而,我很困惑,爲什麼它首先需要HttpModule
,因爲這是一個ProductService
依賴關係,並且我正在使用提供者嘲笑ProductService
。
所以我的問題總之是爲什麼測試告訴我,當被測試的類不使用它時,我需要這種依賴關係?
產品detail.component.ts
import {Component, OnInit} from '@angular/core';
import {ActivatedRoute, Params} from "@angular/router";
import {ProductService} from "../product.service";
import {Product} from "../product";
import 'rxjs/add/operator/switchMap';
@Component({
selector: 'app-product-detail',
templateUrl: './product-detail.component.html',
styleUrls: ['./product-detail.component.css'],
providers: [ProductService]
})
export class ProductDetailComponent implements OnInit {
product: Product;
constructor(
private productService: ProductService,
private route: ActivatedRoute,
) { }
ngOnInit() {
this.route.params
.switchMap((params: Params) => this.productService.getProduct(+params['id']))
.subscribe(product => this.product = product);
}
}
product.service.ts
import {Injectable} from "@angular/core";
import {Product} from "./product";
import {Http} from "@angular/http";
import "rxjs/add/operator/toPromise";
@Injectable()
export class ProductService {
private products: Product[];
constructor(private http: Http) { }
getProducts(): Promise<Product[]> {
return this.http
.get('/api/products/')
.toPromise()
.then(response => response.json() as Product[])
.catch(error => {
console.error('An error occurred', error);
return Promise.reject(error.message || error)
});
}
getProduct(id: number): Promise<Product> {
return this.http
.get(`/api/products/${id}`)
.toPromise()
.then(response => response.json() as Product)
.catch(error => {
console.error('An error occurred', error);
return Promise.reject(error.message || error)
});
}
}
產品detail.component.spec.ts:
import {async, ComponentFixture, TestBed} from "@angular/core/testing";
import {ProductDetailComponent} from "./product-detail.component";
import {ActivatedRoute} from "@angular/router";
import {Observable} from "rxjs";
import {ProductService} from "../product.service";
import {Product} from "../product";
import {By} from "@angular/platform-browser";
import {DebugElement} from "@angular/core";
import {HttpModule} from "@angular/http";
describe('ProductDetailComponent',() => {
let component: ProductDetailComponent;
let fixture: ComponentFixture<ProductDetailComponent>;
let debugElement: DebugElement;
let element: HTMLElement;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ProductDetailComponent],
//imports: [HttpModule], //un-commenting this fixes the breakages
providers: [{
provide: ActivatedRoute,
useValue: {params: Observable.from([{'id': 1}])},
}, {
provide: ProductService,
useValue: {
getProduct: (id: number) => Promise.resolve(new Product(id, 'Example Product Name', 20))
}
}]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(ProductDetailComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create',() => {
expect(component).toBeTruthy();
});
it('should be stable',() => {
fixture.whenStable().then(() => {
expect(fixture.isStable()).toBe(true);
});
});
it('should display the title',() => {
fixture.whenStable().then(() => {
debugElement = fixture.debugElement.query(By.css('.name'));
element = debugElement.nativeElement;
expect(element.textContent).toEqual('Example Product Name')
});
});
it('should display the price',() => {
fixture.whenStable().then(() => {
debugElement = fixture.debugElement.query(By.css('.span'));
element = debugElement.nativeElement;
expect(element.textContent).toEqual('$ 20.0')
});
});
});