问题描述
我有一个BreakpointService,它告诉我-根据屏幕宽度-应该在其中显示SidebarMode的SidebarMode(关闭-缩小-打开).
I have a BreakpointService, which tells me - depending on the screen width - in which SidebarMode (closed - minified - open) I should display my Sidebar.
这是服务的主要部分:
constructor(private breakpointObserver: BreakpointObserver) {
this.closed$ = this.breakpointObserver.observe(['(min-width: 1024px)']).pipe(
filter((state: BreakpointState) => !state.matches),
mapTo(SidebarMode.Closed)
);
this.opened$ = this.breakpointObserver.observe(['(min-width: 1366px)']).pipe(
filter((state: BreakpointState) => state.matches),
mapTo(SidebarMode.Open)
);
const minifiedStart$: Observable<boolean> = this.breakpointObserver.observe(['(min-width: 1024px)']).pipe(map(state => state.matches));
const minifiedEnd$: Observable<boolean> = this.breakpointObserver.observe(['(max-width: 1366px)']).pipe(map(state => state.matches));
this.minified$ = minifiedStart$.pipe(
flatMap(start => minifiedEnd$.pipe(map(end => start && end))),
distinctUntilChanged(),
filter(val => val === true),
mapTo(SidebarMode.Minified)
);
this.observer$ = merge(this.closed$, this.minified$, this.opened$);
}
在这一行中,我可以订阅事件:
with this line I can subscribe to the events:
this.breakpointService.observe().subscribe();
现在,我想在单元测试中测试不同的模式,但是我不知道
Now, I would like to test the different modes within a unit test, but I don't know
如何在测试中模拟window.screen.width属性
我尝试了几件事,但对我没有任何帮助.
I tried several things, but nothing worked out for me.
这是我到目前为止的测试设置:
This is my test-setup so far:
describe('observe()', () => {
function resize(width: number): void {
// did not work
// window.resizeTo(width, window.innerHeight);
// (<any>window).screen = { width: 700 };
// spyOn(window, 'screen').and.returnValue(...)
}
let currentMode;
beforeAll(() => {
service.observe().subscribe(mode => (currentMode = mode));
});
it('should return Observable<SidebarMode>', async () => {
resize(1000);
expect(Object.values(SidebarMode).includes(SidebarMode[currentMode])).toBeTruthy();
});
xit('should return SidebarMode.Closed', async () => {
resize(600);
expect(currentMode).toBe(SidebarMode.Closed);
});
xit('should return SidebarMode.Minified', async () => {
resize(1200);
expect(currentMode).toBe(SidebarMode.Minified);
});
xit('should return SidebarMode.Open', async () => {
resize(2000);
expect(currentMode).toBe(SidebarMode.Open);
});
});
推荐答案
模拟角材料BreakpointObserver
我猜你不是真的要模拟window.screen,实际上你是要模拟BreakpointObserver
.毕竟,无需测试他们的代码,您只想测试您的代码是否可以正确响应BreakpointObserver.observe()
在不同屏幕尺寸下返回的可观察值.
Mocking Angular Material BreakpointObserver
I'm guessing you don't really want to mock window.screen, you actually want to mock BreakpointObserver
. After all, no need to test their code, you just want to test that your code responds properly to the observable returned by BreakpointObserver.observe()
with different screen sizes.
有很多不同的方法可以做到这一点.为了说明一种方法,我将 STACKBLITZ放在一起与您的代码一起展示了我将如何处理此问题.需要注意的事情与上面的代码不同:
There are a lot of different ways to do this. To illustrate one method, I put together a STACKBLITZ with your code showing how I would approach this. Things to note that differ from what your code is above:
- 您的代码在构造函数中设置了可观察对象.因此,必须在实例化服务之前更改模拟,因此您将看到对
resize()
的调用发生在service = TestBed.get(MyService);
调用之前. - 我用spyObj嘲笑了
BreakpointObserver
,并称其为假货函数代替BreakpointObserver.observe()
方法.这伪函数使用我设置的过滤器,并设置了想要的结果来自各种比赛.他们全都以错误开始,因为值将根据所需的屏幕尺寸而变化模拟,并且由您使用的resize()
函数设置在上面的代码中.
- Your code sets up the observables in the constructor. Because of this the mock has to be changed BEFORE the service is instantiated, so you will see the call to
resize()
happens before theservice = TestBed.get(MyService);
call. - I mocked
BreakpointObserver
with a spyObj, and called a fakefunction in place of theBreakpointObserver.observe()
method. Thisfake function uses a filter I had set up with the results I wantedfrom the various matches. They all started as false, because thevalues would change depending on what screen size is desired to bemocked, and that is set up by theresize()
function you were usingin the code above.
这是新建议的describe
函数的StackBlitz中的一个片段:
Here is a snip from the StackBlitz of the new suggested describe
function:
describe('MyService', () => {
let service: MyService;
const matchObj = [ // initially all are false
{ matchStr: '(min-width: 1024px)', result: false },
{ matchStr: '(min-width: 1366px)', result: false },
{ matchStr: '(max-width: 1366px)', result: false }
];
const fakeObserve = (s: string[]): Observable<BreakpointState> => from(matchObj).pipe(
filter(match => match.matchStr === s[0]),
map(match => <BreakpointState>{ matches: match.result, breakpoints: {} })
);
const bpSpy = jasmine.createSpyObj('BreakpointObserver', ['observe']);
bpSpy.observe.and.callFake(fakeObserve);
beforeEach(() => {
TestBed.configureTestingModule({
imports: [ ],
providers: [ MyService,
{ provide: BreakpointObserver, useValue: bpSpy }
]
});
});
it('should be createable', () => {
service = TestBed.get(MyService);
expect(service).toBeTruthy();
});
describe('observe()', () => {
function resize(width: number): void {
matchObj[0].result = (width >= 1024) ? true : false;
matchObj[1].result = (width >= 1366) ? true : false;
matchObj[2].result = (width <= 1366) ? true : false;
}
it('should return Observable<SidebarMode>', () => {
resize(1000);
service = TestBed.get(MyService);
service.observe().subscribe(mode => {
expect(Object.values(SidebarMode).includes(SidebarMode[mode])).toBeTruthy();
});
});
it('should return SidebarMode.Closed', () => {
resize(600);
service = TestBed.get(MyService);
service.observe().subscribe(mode => expect(mode).toBe(SidebarMode.Closed));
});
it('should return SidebarMode.Minified', () => {
resize(1200);
service = TestBed.get(MyService);
service.observe().subscribe(mode => expect(mode).toBe(SidebarMode.Minified));
});
it('should return SidebarMode.Open', () => {
resize(2000);
service = TestBed.get(MyService);
service.observe().subscribe(mode => expect(mode).toBe(SidebarMode.Open));
});
});
});
我希望这对您有帮助
这篇关于如何在Jasmine的Angular单元测试中模拟window.screen.width的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!