Testing the controller passed to an Angular Material Dialog instance
首先,我试图对传递给" Angular Material Dialog"实例的控制器进行单元测试。
作为一个一般性问题,单独测试这种控制器还是通过实际调用
我正在尝试第一种方法,但是我遇到了一些问题,主要与Angular Material如何将" locals "绑定到控制器有关。
这是我用来在源代码中调用对话框的代码,该代码可以正常工作:
1 2 3 4 5 6 7 8 9 | $mdDialog.show({ controller: 'DeviceDetailController', controllerAs: 'vm', locals: {deviceId:"123"}, bindToController: true, templateUrl: 'admin/views/deviceDetail.html', parent: angular.element(document.body), targetEvent: event }); |
我不相信文档已更新,但是从0.9.0版本开始,在调用构造函数时,控制器可以使用本地语言(请参阅Github上的此问题)。这是受测试的控制器构造函数的精简版本,因此您可以看到为什么当控制器为" instantiated"时,为什么我需要传递变量并使其可用:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | function DeviceDetailController(devicesService) { var vm = this; vm.device = {}; // vm.deviceId = null; //this field is injected when the dialog is created, if there is one. For some reason I can't pre-assign it to null. activate(); ////////// function activate() { if (vm.deviceId != null) { loadDevice(); } } function loadDevice() { devicesService.getDeviceById(vm.deviceId) .then(function(data) { vm.device = data.collection; }; } } |
我正在尝试在调用deviceId并将其传递给构造函数之前,将设备分配给vm.device。
测试(jasmine和西农,由业力经营):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | describe('DeviceDetailController', function() { var $controllerConstructor, scope, mockDevicesService; beforeEach(module("admin")); beforeEach(inject(function ($controller, $rootScope) { mockDevicesService = sinon.stub({ getDeviceById: function () {} }); $controllerConstructor = $controller; scope = $rootScope.$new(); })); it('should get a device from devicesService if passed a deviceId', function() { var mockDeviceId = 3; var mockDevice = {onlyIWouldHaveThis: true}; var mockDeviceResponse = {collection: [mockDevice]}; var mockDevicePromise = { then: function (cb) { cb(mockDeviceResponse); } }; var mockLocals = {deviceId: mockDeviceId, $scope: scope}; mockDevicesService.getDeviceById.returns(mockDevicePromise); var ctrlConstructor = $controllerConstructor('DeviceDetailController as vm', mockLocals, true); angular.extend(ctrlConstructor.instance, mockLocals); ctrlConstructor(); expect(scope.vm.deviceId).toBe(mockDeviceId); expect(scope.vm.device).toEqual(mockDevice); }); }); |
运行此命令时,第一个断言通过,第二个断言失败(" Expected Object({})等于Object({onlyIWouldHaveThis:true})。"),这表明我将deviceId注入到其中控制器的作用域,但显然不能及时使activate()方法中的if子句看到它。
您会注意到,我正在尝试通过调用$ controller()并将第三个参数设置为\\'true \\'来模仿Angular Material使用的基本过程,这将导致$ controller()返回控制器构造函数,而不是最终的控制器。然后,我应该能够使用局部变量扩展构造函数(就像Angular Material在上面链接的代码中所做的那样),然后调用构造函数来实例化控制器。
我已经尝试了很多方法,包括通过调用
感谢您的帮助!
我要尝试的第一件事是从对$ controller的调用中丢失\\ as as vm \\。您可以仅将返回值用于您的期望值,而不是测试范围。
尝试一下:
1 2 3 4 5 6 | var ctrlConstructor = $controllerConstructor('DeviceDetailController', mockLocals, true); angular.extend(ctrlConstructor.instance, mockLocals); var vm = ctrlConstructor(); expect(vm.deviceId).toBe(mockDeviceId); expect(vm.device).toEqual(mockDevice); |