Sea*_*ean 6 javascript unit-testing angularjs karma-jasmine angular-material
首先,我试图对传递给Angular Material Dialog实例的控制器进行单元测试.
作为一般性问题,单独测试这样的控制器或实际调用$mdDialog.show()是否更有意义?
我正在尝试第一种方法,但我遇到了一些问题,主要与Angular Material如何将"locals"绑定到控制器有关.
这是我用来在源代码中调用对话框的代码,它按预期工作:
$mdDialog.show({
controller: 'DeviceDetailController',
controllerAs: 'vm',
locals: {deviceId: "123"},
bindToController: true,
templateUrl: 'admin/views/deviceDetail.html',
parent: angular.element(document.body),
targetEvent: event
});
Run Code Online (Sandbox Code Playgroud)
我不相信文档已经更新,但是从版本0.9.0开始,在调用构造函数时控制器可以使用本地文件(请参阅Github上的这个问题).这是一个被测试的控制器构造函数的精简版本,因此您可以看到为什么我需要传递变量并在控制器"实例化"时可用:
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;
};
}
}
Run Code Online (Sandbox Code Playgroud)
我试图测试在调用deviceId之前将deviceId传入构造函数时将设备分配给vm.device.
测试(茉莉和sinon,由业力运行):
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);
});
});
Run Code Online (Sandbox Code Playgroud)
当我运行它时,第一个断言通过,第二个断言失败("Expected Object({})"等于Object({onlyIWouldHaveThis:true})."),这表明deviceId正被注入控制器的范围,但是显然没有及时使用activate()方法中的if子句来查看它.
你会注意到我试图通过调用$ controller()并将第三个参数设置为'true' 来模仿Angular Material使用的基本过程,这会导致$ controller()返回控制器构造函数,而不是结果控制器.然后,我应该能够使用我的局部变量扩展构造函数(就像Angular Material在链接到上面的代码中所做的那样),然后调用构造函数来实例化控制器.
我已经尝试了很多东西,包括通过调用将隔离范围传递给控制器$rootScope.$new(true),没有效果(实际上我不能说我完全理解隔离范围,但是默认情况下$ mdDialog使用它).
任何帮助表示赞赏!
我要尝试的第一件事是从您对 $controller 的调用中丢失“as vm”。您可以仅使用预期的返回值,而不是测试范围。
尝试这个:
var ctrlConstructor = $controllerConstructor('DeviceDetailController', mockLocals, true);
angular.extend(ctrlConstructor.instance, mockLocals);
var vm = ctrlConstructor();
expect(vm.deviceId).toBe(mockDeviceId);
expect(vm.device).toEqual(mockDevice);
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1409 次 |
| 最近记录: |