如何为UI5中attachBrowserEvent编写QUnit测试提升代码覆盖率
问题:QUnit测试中Stub
attachBrowserEvent 及解决__sapUiIntegration_card未定义错误 场景说明
需要为控制器中指定代码块编写QUnit测试以提升覆盖率,但运行测试时触发Cannot read properties of undefined (reading '__sapUiIntegration_card')错误,同时不清楚如何Stub attachBrowserEvent方法。
控制器核心代码(需测试部分)
sap.ui.define([ "sap/ui/core/mvc/Controller", "sap/ui/model/json/JSONModel", "sap/m/MessageToast", ], function (Controller,JSONModel,MessageToast) { "use strict"; return Controller.extend("com.sap.onesm.supplier.ext.slpCard.supplierContactDetails.Main", { // 其他方法省略 loadData: function(channelId, eventId, oData) { console.log('In callback supplierContactDetails.loadData().. '); let oController = this; var data = oData.vendorData; // 需测试的代码块 oController.oCard = oController.getView().getParent().getComponentData().__sapUiIntegration_card; oController.oCard.getCardHeader().attachBrowserEvent("click",function(){ oController.onPressNavToSMContacts(oData.smVendorId, oData.s4Url); }); // 需测试的代码块结束 let loaderStatus = oController.getView().getModel("cardState"); // 后续逻辑省略 return data[0]; }, // 其他方法省略 }); });
现有测试代码
QUnit.module("Supplier Contacts Card"); let oController = new SupplierContactController(); oController.getView = function() { return { setModel: function(){}, getModel: function(){ return { setProperty: function () { } } }, getParent: function () { return { getComponentData: function() { } } } }; }; QUnit.test("check for data", function(assert) { let expectedVendorData = [{"Supplier Name":"Ariba Supplier Risk Demo Supplier 111620", "SM Vendor ID":"S25187250", "Primary contact first name": "Drew", "Primary contact last name": "Myers", "Primary contact email": "j.drew.myers@gmail.com"}]; let expectedOData = {"vendorData" : expectedVendorData, "smVendorId": "S25187250", "s4Url": "sampleURL"}; oController.onInit(); let loadDataResult = oController.loadData("", "", expectedOData); assert.strictEqual(loadDataResult[0][["contactName"]],"Drew Myers","Contact Name Matched"); assert.strictEqual(loadDataResult[0][["Primary contact email"]],"j.drew.myers@gmail.com","Email Id Matched"); });
错误信息
Died on test #1 at QUnit.test (https://ui5.sap.com/resources/sap/ui/thirdparty/sinon-qunit.js:34:356) at http://localhost:8080/test/unit/controller/SupplierContacts.controller.js:27:11 at https://ui5.sap.com/resources/sap-ui-core.js:10:16806: Cannot read properties of undefined (reading '__sapUiIntegration_card')@ 1 ms Expected: null Message: Diff suppressed as the expected and actual results have an equivalent serialization Source: TypeError: Cannot read properties of undefined (reading '__sapUiIntegration_card') at p.loadData (http://localhost:8080/ext/slpCard/supplierContactDetails/SupplierContact.controller.js:28:85) at Object.<anonymous> (http://localhost:8080/test/unit/controller/SupplierContacts.controller.js:39:42) at Object.i (https://ui5.sap.com/resources/sap/ui/thirdparty/sinon.js:220:476) at Object.e (https://ui5.sap.com/resources/sap/ui/thirdparty/sinon.js:220:794)
解决方案
1. 修复__sapUiIntegration_card未定义问题
补全getComponentData的返回值,添加__sapUiIntegration_card对象,并为其提供getCardHeader方法,该方法返回包含attachBrowserEvent的模拟对象。
2. Stub attachBrowserEvent并验证逻辑
使用Sinon.js的stub模拟attachBrowserEvent,同时用spy监听目标方法,验证点击事件触发时的调用逻辑。
修改后的测试代码
QUnit.module("Supplier Contacts Card"); let oController = new SupplierContactController(); let attachBrowserEventStub; let onPressSpy; QUnit.beforeEach(function() { // 创建spy监听导航方法,用于验证调用 onPressSpy = sinon.spy(oController, "onPressNavToSMContacts"); // 完整模拟视图-组件数据-card的调用链 oController.getView = function() { // 模拟cardHeader对象,包含attachBrowserEvent stub const oCardHeader = { attachBrowserEvent: sinon.stub().callsArg(1) // 自动触发传入的回调函数,模拟点击 }; return { setModel: function(){}, getModel: function(){ return { setProperty: function () { } } }, getParent: function () { return { getComponentData: function() { return { __sapUiIntegration_card: { getCardHeader: function() { return oCardHeader; } } }; } } } }; }; }); QUnit.afterEach(function() { // 恢复spy,避免影响其他测试 onPressSpy.restore(); }); QUnit.test("check for data and card header click event", function(assert) { let expectedVendorData = [{"Supplier Name":"Ariba Supplier Risk Demo Supplier 111620", "SM Vendor ID":"S25187250", "Primary contact first name": "Drew", "Primary contact last name": "Myers", "Primary contact email": "j.drew.myers@gmail.com"}]; let expectedOData = {"vendorData" : expectedVendorData, "smVendorId": "S25187250", "s4Url": "sampleURL"}; oController.onInit(); let loadDataResult = oController.loadData("", "", expectedOData); // 验证数据处理逻辑 assert.strictEqual(loadDataResult.contactName,"Drew Myers","Contact Name Matched"); assert.strictEqual(loadDataResult["Primary contact email"],"j.drew.myers@gmail.com","Email Id Matched"); // 验证attachBrowserEvent是否被正确调用 const oCardHeader = oController.getView().getParent().getComponentData().__sapUiIntegration_card.getCardHeader(); assert.ok(oCardHeader.attachBrowserEvent.calledOnceWith("click"), "attachBrowserEvent called with click event"); // 验证点击回调触发时,导航方法是否被正确调用 assert.ok(onPressSpy.calledOnceWith(expectedOData.smVendorId, expectedOData.s4Url), "onPressNavToSMContacts called with correct parameters"); });
关键说明
- 完整模拟调用链:补全
getView().getParent().getComponentData().__sapUiIntegration_card.getCardHeader()的每一层返回值,避免undefined错误。 - Stub事件绑定方法:用Sinon的stub替代
attachBrowserEvent,并通过callsArg(1)自动触发回调,模拟用户点击行为。 - Spy验证业务逻辑:通过spy监听
onPressNavToSMContacts,验证点击事件是否正确触发了目标方法,且参数符合预期。
内容的提问来源于stack exchange,提问作者Abhilasha Dahiya
相关产品推荐
相关产品推荐

