Angular5+Ionic3名片扫描功能单元测试失败求助
解决Angular5+Ionic3名片扫描功能单元测试失败问题
咱们先把根源说透:单元测试跑在Node.js环境里,没有原生设备的相机插件,也没法真的渲染Ionic的Loading组件——这就是为啥移动端正常但测试卡壳的核心原因。咱们的解决思路很明确:把所有依赖的原生插件和Ionic服务都Mock掉,让测试代码能模拟真实的执行流程。
1. 先梳理你的代码依赖
你的scanBusinessCard方法大概率用到了这些东西:
- 可选的
FabContainer(用来关闭浮动操作按钮) - 相机插件(比如
cordova-plugin-camera的Camera类) - Ionic的
LoadingController(显示上传中的Loading提示) - 图片上传服务(发起HTTP请求上传扫描后的图片)
2. 给测试写Mock依赖
2.1 Mock Ionic的LoadingController
在测试文件里写个假的LoadingController,模拟它的创建、显示和关闭方法:
class MockLoadingController { create() { return { present: jasmine.createSpy('present'), dismiss: jasmine.createSpy('dismiss') }; } }
2.2 Mock相机插件
如果用的是cordova-plugin-camera,咱们模拟它的getPicture方法,直接返回测试用的图片数据:
class MockCamera { static getPicture(options) { // 模拟相机返回一张测试用的base64图片 return Promise.resolve('test-image-base64-string'); } }
2.3 Mock FabContainer(如果用到的话)
如果方法里需要关闭浮动按钮,也得给FabContainer写个Mock:
class MockFabContainer { close = jasmine.createSpy('close'); }
3. 把真实依赖换成Mock
在测试模块的配置里,把真实的服务替换成咱们写的Mock:
beforeEach(async(() => { TestBed.configureTestingModule({ declarations: [YourTargetComponent], providers: [ { provide: LoadingController, useClass: MockLoadingController }, { provide: Camera, useClass: MockCamera }, // 要是有上传服务这类其他依赖,也得一起Mock ] }).compileComponents(); }));
4. 写具体的测试用例
现在可以验证方法的逻辑是否正确了:
测试用例1:传入FabContainer时会关闭它
it('should close the fab container when it\'s provided', () => { const mockFab = new MockFabContainer(); component.scanBusinessCard(mockFab); expect(mockFab.close).toHaveBeenCalled(); });
测试用例2:扫描开始显示Loading,上传完成关闭Loading
it('should show loading when scanning starts and dismiss it after upload', async(() => { const loadingCtrl = TestBed.inject(LoadingController); const mockLoading = loadingCtrl.create(); component.scanBusinessCard(); // 验证Loading被创建并显示 expect(loadingCtrl.create).toHaveBeenCalled(); expect(mockLoading.present).toHaveBeenCalled(); // 等待异步操作完成 await fixture.whenStable(); // 验证上传完成后Loading被关闭 expect(mockLoading.dismiss).toHaveBeenCalled(); }));
测试用例3:处理相机返回的图片并触发上传
it('should process the scanned image and trigger upload', async(() => { // 假设你有个上传服务,先Mock它 const uploadService = TestBed.inject(UploadService); spyOn(uploadService, 'uploadImage').and.returnValue(Promise.resolve({ success: true })); component.scanBusinessCard(); await fixture.whenStable(); // 验证上传方法被调用,且传入了测试图片数据 expect(uploadService.uploadImage).toHaveBeenCalledWith('test-image-base64-string'); }));
5. 额外注意点
- 如果你的相机插件是通过
navigator.camera访问的,得在测试环境全局Mock它:beforeEach(() => { (window as any).navigator.camera = { getPicture: (options, success, error) => success('test-image-base64-string') }; }); - 所有异步操作一定要用
async/await或者fakeAsync/tick处理,别让测试提前结束。 - 别忘了写错误处理的测试用例:比如Mock相机返回失败的Promise,验证你的代码会不会正确捕获错误、关闭Loading。
内容的提问来源于stack exchange,提问作者VBDOTNET
相关产品推荐
相关产品推荐

