Angular 角度测试间谍没有被调用
我在配置角度测试时遇到问题,无法正常工作。具体的问题是,我的间谍似乎没有工作。我对Angular是个新手,我试图理解如何编写测试。背景是这是我的第一个Angular应用程序(使用最新版本的CLI 7.x)。这是一个简单的幻灯片。幻灯片效果很好,但我只是想让测试正常进行 第一部分是应用程序需要从JavaScript window.location获取href。基于Stackoverflow和其他方面的建议,我创建了一个类来包装窗口,以便对其进行测试。下面是一个名为windowobject.service.ts的服务的外观:Angular 角度测试间谍没有被调用,angular,typescript,unit-testing,mocking,karma-jasmine,Angular,Typescript,Unit Testing,Mocking,Karma Jasmine,我在配置角度测试时遇到问题,无法正常工作。具体的问题是,我的间谍似乎没有工作。我对Angular是个新手,我试图理解如何编写测试。背景是这是我的第一个Angular应用程序(使用最新版本的CLI 7.x)。这是一个简单的幻灯片。幻灯片效果很好,但我只是想让测试正常进行 第一部分是应用程序需要从JavaScript window.location获取href。基于Stackoverflow和其他方面的建议,我创建了一个类来包装窗口,以便对其进行测试。下面是一个名为windowobject.serv
import { Injectable } from '@angular/core';
function getWindow (): any {
return window;
}
@Injectable({
providedIn: 'root'
})
export class WindowObjectService {
constructor() { }
get browserWindow(): any {
return getWindow();
}
}
这很好,但问题是在测试中模拟它。我的测试名为photos.component.spec.ts:
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { HttpClientTestingModule } from '@angular/common/http/testing';
import { PhotosComponent } from './photos.component';
import { NgbModule } from '@ng-bootstrap/ng-bootstrap' ;
import { WindowObjectService } from '../services/windowobject.service';
import { environment } from '../../environments/environment';
const expectedId = 916;
class MockWindowObjectService {
browserWindow(): any {
return { window: {
location: {
href: environment.baseUrl + '/angular/slideshow/index.html?id=' + expectedId
}
}
};
}
}
describe('PhotosComponent', () => {
let component: PhotosComponent;
let fixture: ComponentFixture<PhotosComponent>;
let windowService: MockWindowObjectService;
let windowSpy;
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [ HttpClientTestingModule, NgbModule ],
declarations: [PhotosComponent],
providers: [ { provide: WindowObjectService, useClass: MockWindowObjectService } ]
})
.compileComponents().then(() => {
windowService = TestBed.get(WindowObjectService);
fixture = TestBed.createComponent(PhotosComponent);
component = fixture.componentInstance;
});
}));
it('should create', () => {
expect(component).toBeTruthy();
});
it('should call window object service', () => {
windowSpy = spyOn(windowService, 'browserWindow').and.callThrough();
expect(windowService.browserWindow).toHaveBeenCalled();
});
});
从'@angular/core/testing'导入{async,ComponentFixture,TestBed};
从'@angular/common/http/testing'导入{HttpClientTestingModule};
从“./photos.component”导入{PhotosComponent};
从'@ng bootstrap/ng bootstrap'导入{NgbModule};
从“../services/windowobject.service”导入{WindowObjectService};
从“../../environments/environment”导入{environment};
const expectedId=916;
类MockWindowObjectService{
browserWindow():任何{
返回{窗口:{
地点:{
href:environment.baseUrl+'/angular/slideshow/index.html?id='+expectedId
}
}
};
}
}
描述('PhotosComponent',()=>{
let组件:PhotosComponent;
let夹具:组件夹具;
让Windows服务:MockWindowObjectService;
让我们一起来吧;
beforeach(异步(()=>{
TestBed.configureTestingModule({
导入:[HttpClientTestingModule,NgbModule],
声明:[组件],
提供程序:[{提供:WindowObjectService,useClass:MockWindowObjectService}]
})
.compileComponents()。然后(()=>{
windowService=TestBed.get(WindowObjectService);
fixture=TestBed.createComponent(PhotoComponent);
组件=fixture.componentInstance;
});
}));
它('应该创建',()=>{
expect(component.toBeTruthy();
});
它('应该调用窗口对象服务',()=>{
windowSpy=spyOn(WindowsService,'browserWindow')。和.callThrough();
期望(WindowsService.browserWindow).toHaveBeenCalled();
});
});
我在这里要做的是模拟窗口对象服务并确定它已被调用。一旦我确认它被成功调用,我想写的下一个测试就是确认它返回模拟值。我尝试了很多不同的测试配置,这只是最新的一次迭代,但似乎没有任何效果。我只犯了一个错误,那就是间谍没被叫来。有没有办法解决这个问题,让模拟和间谍工作
更新,添加photos.component.ts。这使用ng引导轮转和分页来显示幻灯片,每次显示一个图像,可以使用轮转箭头或分页组件进行导航。照片集合id来自url中的查询字符串值
import { Component, OnInit, ViewChild } from '@angular/core';
import { PhotosService } from '../services/photos.service';
import { IPhoto } from '../models/photo';
import { NgbCarousel, NgbCarouselConfig, NgbPaginationConfig } from '@ng-bootstrap/ng-bootstrap';
import { WindowObjectService } from '../services/windowobject.service';
@Component({
selector: 'app-photos',
templateUrl: './photos.component.html',
styleUrls: ['./photos.component.scss'],
providers: [NgbCarouselConfig, WindowObjectService]
})
export class PhotosComponent implements OnInit {
// reference to "photosCarousel"
@ViewChild('photosCarousel') photosCarousel: NgbCarousel;
private _photosService: any;
private _windowService: WindowObjectService;
errorMessage: string;
photos: IPhoto[] = new Array;
page = 1;
collectionSize: number;
tripReportId: string;
constructor(carouselConfig: NgbCarouselConfig, paginationConfig: NgbPaginationConfig, phototsService: PhotosService,
windowService: WindowObjectService) {
carouselConfig.showNavigationArrows = true;
carouselConfig.showNavigationIndicators = false;
carouselConfig.interval = 0; // Amount of time in milliseconds before next slide is shown.
carouselConfig.wrap = false;
paginationConfig.pageSize = 1;
paginationConfig.maxSize = 5;
paginationConfig.size = 'sm';
paginationConfig.boundaryLinks = false;
this._photosService = phototsService;
this._windowService = windowService;
}
ngOnInit() {
console.log('this._windowService.browserWindow.location.href', this._windowService.browserWindow.location.href);
this.tripReportId = this._windowService.browserWindow.location.href.split('?')[1].split('=')[1];
this._photosService.getPhotos(this.tripReportId).subscribe(
photos => {
this.photos = photos;
this.collectionSize = photos.length;
},
error => this.errorMessage = <any>error
);
this.collectionSize = this.photos.length;
}
pageChanged(pageNumber: number): void {
this.photosCarousel.select(pageNumber.toString());
}
public onSlide(slideData) {
this.page = slideData.current;
}
}
从'@angular/core'导入{Component,OnInit,ViewChild};
从“../services/photos.service”导入{photoservice};
从“../models/photo”导入{IPhoto};
从'@ng bootstrap/ng bootstrap'导入{NgbCarousel,NgbCarouselConfig,NgbPaginationConfig};
从“../services/windowobject.service”导入{WindowObjectService};
@组成部分({
选择器:“应用程序照片”,
templateUrl:'./photos.component.html',
样式URL:['./photos.component.scss'],
提供者:[NgbCarouselConfig,WindowObjectService]
})
导出类组件实现OnInit{
//对“photosCarousel”的引用
@ViewChild(“photocarousel”)photocarousel:NgbCarousel;
私人影印服务:任何;
private\u windowService:WindowObjectService;
错误消息:字符串;
照片:IPhoto[]=新阵列;
page=1;
集合大小:数量;
tripReportId:字符串;
构造函数(carouseConfig:NgbCarouselConfig,分页配置:NgbPaginationConfig,phototsService:photoservice,
WindowsService:WindowObjectService){
carouselConfig.showNavigationRows=true;
carouselConfig.showNavigationIndicators=false;
carouselConfig.interval=0;//显示下一张幻灯片之前的时间量(毫秒)。
carouselConfig.wrap=false;
paginationConfig.pageSize=1;
paginationConfig.maxSize=5;
paginationConfig.size='sm';
paginationConfig.boundaryLinks=false;
这._photoservice=phototsService;
这是.\u windowService=windowService;
}
恩戈尼尼特(){
log('this.\u windowService.browserWindow.location.href',this.\u windowService.browserWindow.location.href');
this.tripReportId=this._windowService.browserWindow.location.href.split('?')[1]。split('=')[1];
此.\u photosService.getPhotos(此.tripReportId)。订阅(
照片=>{
this.photos=照片;
this.collectionSize=photos.length;
},
error=>this.errorMessage=错误
);
this.collectionSize=this.photos.length;
}
pageChanged(pageNumber:number):无效{
this.photocarousel.select(pageNumber.toString());
}
公共滑道(滑道数据){
this.page=slideData.current;
}
}
好的,这是我把你的代码放到这里时发现的
- 正如我所怀疑的,您需要调用
,以便执行ngOnInit()fixture.detectChanges()
- 因为您在@Component decorator的providers数组中声明了
,所以不能在默认providers数组中替换为mock。相反,您需要使用WindowObjectService
,如StackBlitz中所示overrideComponent()
- 组件将WindowsService设置为构造函数中的组件变量。正因为如此,它使这个v