Angular 2 v.2.0.0 - TS + karma + jasmine。
我测试了这个功能 - 回到点击以前的页面:
public isClick: boolean = false;
public backClicked(location: Location): void {
if (!this.isClick) {
this.isClick = true;
this.location.back();
}
}
这是我的考验:
describe("NavBarComponent", () => {
describe("function backClicked(): void", () => {
let testNavBarComponent: NavBarComponent;
let loc: Location;
beforeEach(() => {
testNavBarComponent = new NavBarComponent(null);
});
loc = jasmine.createSpyObj("Location", ["back"]);
it ("It is backClicked() function test", () => {
testNavBarComponent.backClicked(loc);
expect(loc.back).toHaveBeenCalledTimes(1);
});
});
});
运行测试后,我遇到了这个错误:TypeError: Cannot read property 'back' of null
。可能是createSpyObj
或其他问题的问题?
答案 0 :(得分:3)
在backClicked函数中,您将调用位置this.location
的类实例,而不是传递给函数location
的位置实例。我假设您的NavBarComponent由于错误消息而注入了Location(默认情况下,事物是未定义的而不是null)。
您可以执行以下操作:
beforeEach(() => {
// Mock the location here instead, then pass to the NavBarComponent
loc = jasmine.createSpyObj("Location", ["back"]);
testNavBarComponent = new NavBarComponent(loc);
});
或者,我使用Angular的ReflectiveInjector课有好运。可用于模拟Angular 2中测试的依赖关系的文档和文章全都是RC的迭代次数,所以我不能100%确定这被认为是最佳实践 :
import { ReflectiveInjector } from '@angular/core';
import { Location } from '@angular/common';
describe("NavBarComponent", () => {
describe("function backClicked(): void", () => {
let testNavBarComponent: NavBarComponent;
let loc: Location;
beforeEach(() => {
let injector = ReflectiveInjector.resolveAndCreate([
LocationStrategy,
Location
]);
// Get the created object from the injector
loc = injector.get(Location);
// Create the spy. Optionally: .and.callFake(implementation)
spyOn(loc, 'back');
// Create NavBarComponent with the spied Location
testNavBarComponent = new NavBarComponent(loc);
});
it ("It is backClicked() function test", () => {
testNavBarComponent.backClicked(loc);
expect(loc.back).toHaveBeenCalledTimes(1);
});
});
});
修改:现在可以使用TestBed.configureTestingModule完成 :https://blog.thoughtram.io/angular/2016/11/28/testing-services-with-http-in-angular-2.html
使用ReflectiveInjector,您也可以像在app.module中一样声明依赖项。例如,模拟Http服务:
let injector = ReflectiveInjector.resolveAndCreate([
MockBackend
BaseRequestOptions,
{
provide: Http,
useFactory: (backend, options) => {
return new Http(backend, options);
},
deps: [MockBackend, BaseRequestOptions]
}
]);
答案 1 :(得分:1)
Angular在@angular/common
的位置与默认情况下可用的DOM位置对象之间存在混淆。尽管如此,Angular的版本提供了.go()
功能,实际上它只与路由器交互,并且不像DOM对象那样重新加载页面。因此,对于真正的浏览器交互,您必须使用DOM版本,这会给您带来如何测试的问题?
不幸的是,由于它的可写对象,它无法进行间谍活动。 但您可以将其作为值注入组件中。这就是它的样子
export const LOCATION_TOKEN = new InjectionToken<Location>('Window location object');
@Component({
providers: [
{ provide: LOCATION_TOKEN, useValue: window.location }
]
})
export class SomeComponent {
constructor(@Inject(LOCATION_TOKEN) private location: Location) {}
useIt() {
this.location.assign('xxx');
}
}
有关详细信息,请参阅https://angular.io/guide/dependency-injection#non-class-dependencies
答案 2 :(得分:0)
要在Angular中进行测试(如s-f的回答),您可以将LOCATION_TOKEN注入到TestBed中,如下所示:
base_url = test/url
api_url = ${base_url}/api/url
答案 3 :(得分:0)
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ HeroDetailsComponent ],
providers: [ MyHeroService ],
imports: [ RouterTestingModule ],
providers: [{ provide: Location, useClass: SpyLocation }]
})
.compileComponents();
}));
it('should logout from application', async(() => {
const location: Location = TestBed.get(Location);
expect(location.href).toContain('blablabla url');
}));