测试时Spec文件调用真实BarcodeScanner而非Mock,如何修复?
问题分析与解决方案
你的测试失败有三个核心原因:
- ScannerService直接硬编码引用真实的BarcodeScanner,未通过依赖注入获取实例,导致TestBed提供的Mock无法替换真实对象
- Jasmine SpyObj未给
startScan方法设置mock返回值,调用时返回undefined触发catch分支 - 异步测试的断言时机错误,Promise还未resolve就执行了expect
步骤1:改造ScannerService,通过依赖注入获取BarcodeScanner
原Service直接import并使用BarcodeScanner的方式无法被测试框架替换Mock,需改成构造函数注入:
// scanner.service.ts import { Injectable } from '@angular/core'; import { BarcodeScanner, ScanResult } from '@capacitor/barcode-scanner'; @Injectable({ providedIn: 'root' }) export class ScannerService { // 构造函数注入BarcodeScanner类型实例 constructor(private barcodeScanner: typeof BarcodeScanner) {} async startScan(): Promise<string | boolean> { this.barcodeScanner.hideBackground(); // 通过注入的实例调用方法 try { const result = await this.barcodeScanner.startScan(); if (result.hasContent) { console.log(result.content); return result.content; } return false; } catch (error) { console.log("could not activate scanner. Are you on a mobile device?", error); return false; } }; }
步骤2:修正测试用例,完善Mock并正确处理异步
给SpyObj的startScan设置mock返回值,同时调整异步测试的断言逻辑:
// scanner.service.spec.ts import { TestBed, fakeAsync, tick } from '@angular/core/testing'; import { ScannerService } from './scanner.service'; import { BarcodeScanner } from '@capacitor/barcode-scanner'; import { Capacitor } from '@capacitor/core'; describe('ScannerService', () => { let scannerService: ScannerService; let barcodeScannerSpy: jasmine.SpyObj<typeof BarcodeScanner>; let capacitorCoreSpy: jasmine.SpyObj<typeof Capacitor>; beforeEach(() => { // 创建包含startScan方法的SpyObj barcodeScannerSpy = jasmine.createSpyObj('BarcodeScanner', [ 'hideBackground', 'showBackground', 'stopScan', 'checkPermissions', 'openAppSettings', 'checkPermission', 'startScan' ]); // 给startScan设置mock返回值 barcodeScannerSpy.startScan.and.returnValue(Promise.resolve({ hasContent: true, content: 'mockContent', format: 'mockFormat' })); capacitorCoreSpy = jasmine.createSpyObj('Capacitor', ['isNativePlatform']); capacitorCoreSpy.isNativePlatform.and.returnValue(true); TestBed.configureTestingModule({ providers: [ ScannerService, { provide: BarcodeScanner, useValue: barcodeScannerSpy }, { provide: Capacitor, useValue: capacitorCoreSpy } ] }); scannerService = TestBed.inject(ScannerService); }); it('should return mock content when scan succeeds', fakeAsync(() => { let result: string | boolean; scannerService.startScan().then(res => { result = res; }); // 触发Promise的resolve,确保result被赋值 tick(); expect(result).toEqual('mockContent'); // 验证hideBackground方法被调用 expect(barcodeScannerSpy.hideBackground).toHaveBeenCalled(); // 验证startScan方法被调用 expect(barcodeScannerSpy.startScan).toHaveBeenCalled(); })); });
关键修改说明
- 依赖注入改造:通过构造函数注入
BarcodeScanner类型,让TestBed可以用Mock替换真实实现 - SpyObj完善:在创建SpyObj时加入
startScan方法,通过and.returnValue设置mock的Promise返回值 - 异步处理修正:使用
fakeAsync配合tick(),强制触发Promise的resolve,确保断言时result已被赋值
内容的提问来源于stack exchange,提问作者adamwright000
相关产品推荐
相关产品推荐

