如何为带有@Input属性的Angular 4 AllowOnlyNumbers指令编写单元测试?
没问题!针对你的Angular 4 AllowOnlyNumbers指令(带@Input开关),我整理了一套完整的单元测试方案,覆盖核心场景,直接就能用:
首先先补全指令的基础实现(基于你给出的开头,确保测试逻辑匹配):
import { Directive, HostListener, Input } from '@angular/core'; @Directive({ selector: '[AllowOnlyNumbers]' }) export class AllowOnlyNumbersDirective { @Input() AllowOnlyNumbers: boolean = true; @HostListener('keydown', ['$event']) onKeyDown(event: KeyboardEvent) { if (!this.AllowOnlyNumbers) return; // 允许基础控制键(用于编辑操作) const allowedControlKeys = [ 'Backspace', 'Tab', 'Enter', 'Escape', 'Delete', 'ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown', 'Home', 'End', 'PageUp', 'PageDown' ]; // 允许主键盘数字和小键盘数字 const isNumericKey = /^[0-9]$/.test(event.key) || /^NumPad[0-9]$/.test(event.key); if (allowedControlKeys.includes(event.key) || isNumericKey) { return; } // 阻止非允许的按键 event.preventDefault(); } }
接下来是单元测试文件的编写,我们用Angular的TestBed来搭建测试环境,覆盖所有关键场景:
AllowOnlyNumbersDirective 单元测试
1. 测试环境配置
先创建一个测试组件用来挂载指令,然后配置TestBed:
import { Component, DebugElement } from '@angular/core'; import { ComponentFixture, TestBed } from '@angular/core/testing'; import { By } from '@angular/platform-browser'; import { AllowOnlyNumbersDirective } from './allow-only-numbers.directive'; // 测试宿主组件,用来绑定指令和@Input属性 @Component({ template: `<input [AllowOnlyNumbers]="isEnabled" type="tel" />` }) class TestHostComponent { isEnabled: boolean = true; } describe('AllowOnlyNumbersDirective', () => { let fixture: ComponentFixture<TestHostComponent>; let inputElement: DebugElement; let hostComponent: TestHostComponent; beforeEach(() => { TestBed.configureTestingModule({ declarations: [AllowOnlyNumbersDirective, TestHostComponent] }); fixture = TestBed.createComponent(TestHostComponent); hostComponent = fixture.componentInstance; inputElement = fixture.debugElement.query(By.css('input')); fixture.detectChanges(); });
2. 核心测试用例
🔹 指令启用时,阻止非数字输入
验证字母、符号等非数字按键会被拦截:
it('should block non-numeric keys when directive is enabled', () => { const nonNumericKeys = ['a', '@', '#', '!', 'Z']; nonNumericKeys.forEach(key => { const keydownEvent = new KeyboardEvent('keydown', { key }); spyOn(keydownEvent, 'preventDefault'); inputElement.nativeElement.dispatchEvent(keydownEvent); expect(keydownEvent.preventDefault).toHaveBeenCalled(); }); });
🔹 指令启用时,允许数字键输入
验证主键盘的数字能正常输入:
it('should allow numeric keys when directive is enabled', () => { const numericKeys = ['0', '1', '5', '9']; numericKeys.forEach(key => { const keydownEvent = new KeyboardEvent('keydown', { key }); spyOn(keydownEvent, 'preventDefault'); inputElement.nativeElement.dispatchEvent(keydownEvent); expect(keydownEvent.preventDefault).not.toHaveBeenCalled(); }); });
🔹 指令启用时,允许控制键(退格、Tab等)
确保用户的编辑操作不受影响:
it('should allow control keys when directive is enabled', () => { const controlKeys = ['Backspace', 'Tab', 'ArrowLeft', 'Delete', 'Enter']; controlKeys.forEach(key => { const keydownEvent = new KeyboardEvent('keydown', { key }); spyOn(keydownEvent, 'preventDefault'); inputElement.nativeElement.dispatchEvent(keydownEvent); expect(keydownEvent.preventDefault).not.toHaveBeenCalled(); }); });
🔹 指令启用时,允许小键盘数字键
别忽略用户常用的小键盘输入场景:
it('should allow numpad numeric keys when directive is enabled', () => { const numpadKeys = ['NumPad0', 'NumPad3', 'NumPad9']; numpadKeys.forEach(key => { const keydownEvent = new KeyboardEvent('keydown', { key }); spyOn(keydownEvent, 'preventDefault'); inputElement.nativeElement.dispatchEvent(keydownEvent); expect(keydownEvent.preventDefault).not.toHaveBeenCalled(); }); });
🔹 指令禁用时,允许所有输入
验证@Input设为false时,指令完全失效:
it('should allow all keys when directive is disabled', () => { // 禁用指令 hostComponent.isEnabled = false; fixture.detectChanges(); const testKey = 'a'; const keydownEvent = new KeyboardEvent('keydown', { key: testKey }); spyOn(keydownEvent, 'preventDefault'); inputElement.nativeElement.dispatchEvent(keydownEvent); expect(keydownEvent.preventDefault).not.toHaveBeenCalled(); });
最后关闭describe块:
});
额外建议
如果你的指令还处理了粘贴事件(比如过滤粘贴内容中的非数字),可以添加对应的测试用例,模拟paste事件并验证输入框内容是否被正确过滤。
内容的提问来源于stack exchange,提问作者Nimish goel
相关产品推荐
相关产品推荐

