我这里有一个严肃的问题.我的应用程序依赖于SignalR功能,但由于这一点,我无法编写单元测试.我是测试框架的新手,仅在简单的情况下使用Jasmine.事实证明SignalR对我来说是一个太大的挑战,但我需要了解如何成功测试它.
这是我的CommsApp.ts文件[typescript]:
/// <reference path="References.ts" />
var commsAnimationsModule = angular.module('forge.communications.animations', ['ngAnimate']);
var commsDirectivesModule = angular.module('forge.communications.directives', []);
var commsServicesModule = angular.module('forge.communications.services', []);
var commsFiltersModule = angular.module('forge.communications.filters', []);
var commsApp = angular.module('forge.communications.CommsApp',
[
'ngRoute',
'ngAnimate',
'cfValidation',
'ui.bootstrap',
'forge.communications.animations',
'forge.communications.directives',
'forge.communications.services',
'forge.communications.filters',
'angularFileUpload',
'timeRelative'
]);
commsApp.config(function ($routeProvider: ng.route.IRouteProvider, $locationProvider: any) {
$locationProvider.html5Mode(true);
$routeProvider.
when('/scheduled-messages', {
templateUrl: '/forge/CommsApp/js/Controllers/ScheduledMessageList/ScheduledMessageList.html',
controller: 'ScheduledMessageListController'
}).
when('/geotriggered-messages', {
templateUrl: '/forge/CommsApp/js/Controllers/GeoMessageList/GeoMessageList.html',
controller: 'GeoMessageListController'
}).
when('/scheduled-message/create', {
templateUrl: '/forge/CommsApp/js/Controllers/CreateScheduledMessage/CreateScheduledMessage.html',
controller: 'CreateScheduledMessageController'
}).
when('/scheduled-message/edit/:id', {
templateUrl: '/forge/CommsApp/js/Controllers/EditScheduledMessage/EditScheduledMessage.html',
controller: 'EditScheduledMessageController'
}).
when('/geotriggered-message/create', {
templateUrl: '/forge/CommsApp/js/Controllers/CreateGeotriggeredMessage/CreateGeotriggeredMessage.html',
controller: 'CreateGeotriggeredMessageController'
}).
when('/geotriggered-message/edit/:id', {
templateUrl: '/forge/CommsApp/js/Controllers/EditGeotriggeredMessage/EditGeotriggeredMessage.html',
controller: 'EditGeotriggeredMessageController'
}).
otherwise({
redirectTo: '/scheduled-messages'
});
});
commsApp.run(function ($rootScope: ICommsRootScope, commsSignalrEventService: CommsSignalrEventService, commsMgmtHttpService: CommsMgmtHttpServiceClient) {
// set up the items on the root scope
$rootScope.SelectedLocale = 'en-ie';
$rootScope.ForgeApplicationKey = "9496B737-7AE2-4FBD-B271-A64160759177";
$rootScope.AppVersionString = "1.0.0";
$rootScope.SessionToken = getCookie("ForgeSessionToken");
commsSignalrEventService.initialize().done(() => {
// send any messages about a new user logging in to the application here.
});
// call this at app startup to pre-cache this data for the create and edit pages
commsMgmtHttpService.GetUpdateMessageEditorOptions();
});
function getCookie(name:string) {
var value = "; " + document.cookie;
var parts = value.split("; " + name + "=");
if (parts.length == 2) return parts.pop().split(";").shift();
}
这是测试文件(我删除了大部分代码,因为它无论如何都没有工作,我一直在追逐自己的尾巴):
describe('forge.communications.CommsApp', function () {
beforeEach(module('forge.communications.CommsApp'));
var route, rootScope, proxy, commsSignalrEventService;
beforeEach(inject(function (_$route_, _$rootScope_, _commsSignalrEventService_) {
route = _$route_,
rootScope = _$rootScope_;
commsSignalrEventService = _commsSignalrEventService_;
}));
describe("should map routes to controllers and templates", function () {
it("/scheduled-messages route should be mapped to ScheduledMessageListController", function () {
expect(2).toEqual(2);
expect(route.routes['/scheduled-messages'].controller).toBe('ScheduledMessageListController');
});
});
});
这是CommsSignalREventService.ts文件:
var servicesModule: ng.IModule = angular.module('forge.communications.services');
servicesModule.factory('commsSignalrEventService', function ($rootScope): CommsSignalrEventService {
return new CommsSignalrEventService($rootScope);
});
class CommsSignalrEventService {
private $rootScope: ng.IScope;
private proxy:any = null;
constructor($rootScope) {
this.$rootScope = $rootScope;
}
public initialize(): JQueryPromise<any>{
this.proxy = $.connection['communicationsCenterHub'];
console.log('proxy',this.proxy);
//scheduled messages
this.proxy.client.broadcastScheduledMessageCreatedEvent = (messageId: number) => {
this.$rootScope.$broadcast('comms-message-created', { messageId: messageId });
};
this.proxy.client.broadcastScheduledMessageUpdatedEvent = (messageId: number) => {
this.$rootScope.$broadcast('comms-message-updated', { messageId: messageId });
};
this.proxy.client.broadcastScheduledMessageStateChangedEvent = (messageId: number) => {
this.$rootScope.$broadcast('comms-message-statechanged', { messageId: messageId });
};
this.proxy.client.broadcastScheduledMessageDeletedEvent = (messageId: number) => {
this.$rootScope.$broadcast('comms-message-deleted', { messageId: messageId });
};
//geotriggered messages
this.proxy.client.broadcastGeoMessageCreatedEvent = (messageId: number) => {
this.$rootScope.$broadcast('comms-geomessage-created', { messageId: messageId });
};
this.proxy.client.broadcastGeoMessageUpdatedEvent = (messageId: number) => {
this.$rootScope.$broadcast('comms-geomessage-updated', { messageId: messageId });
};
this.proxy.client.broadcastGeoMessageStateChangedEvent = (messageId: number) => {
this.$rootScope.$broadcast('comms-geomessage-statechanged', { messageId: messageId });
};
this.proxy.client.broadcastGeoMessageDeletedEvent = (messageId: number) => {
this.$rootScope.$broadcast('comms-geomessage-deleted', { messageId: messageId });
};
var promise = $.connection.hub.start();
promise.done(function () {
//console.log('comms signalr hub started');
});
return promise;
}
public RegisterScheduledMessageCreated(messageId: number): void{
this.proxy.server.registerScheduledMessageCreated(messageId);
}
public RegisterScheduledMessageUpdated(messageId: number): void {
this.proxy.server.registerScheduledMessageUpdated(messageId);
}
public RegisterScheduledMessageDeleted(messageId: number): void {
this.proxy.server.registerScheduledMessageDeleted(messageId);
}
public RegisterScheduledMessageStateChanged(messageId: number): void {
this.proxy.server.registerScheduledMessageStateChanged(messageId);
}
public RegisterGeoMessageCreated(messageId: number): void {
this.proxy.server.registerGeoMessageCreated(messageId);
}
public RegisterGeoMessageUpdated(messageId: number): void {
this.proxy.server.registerGeoMessageUpdated(messageId);
}
public RegisterGeoMessageDeleted(messageId: number): void {
this.proxy.server.registerGeoMessageDeleted(messageId);
}
public RegisterGeoMessageStateChanged(messageId: number): void {
this.proxy.server.registerGeoMessageStateChanged(messageId);
}
}
每当我运行karma时,我在命令行中不断看到的错误是forge.communications.CommsApp遇到声明异常FAILED
TypeError:无法在CommsSignalREventService中读取未定义的属性“client”,这意味着CommsSignalREventService.ts文件中的“proxy”变量未定义:
this.proxy = $.connection['communicationsCenterHub'];
console.log('proxy', this.proxy); //resolves to UNDEFINED in tests, works fine in the app
this.proxy.client.broadcastScheduledMessageCreatedEvent = function (messageId) {
_this.$rootScope.$broadcast('comms-message-created', { messageId: messageId });
};
我会感激任何帮助,因为在这个阶段,我试图弄清楚它的时间是多么荒谬.
解决方法:
我认为您的问题是您的实际应用程序引用了SignalR在运行时动态生成的JavaScript.该脚本通常位于“〜/ signalr / hubs”或“〜/ signalr / js”.
此脚本为您创建$.connection [‘communicationsCenterHub’]代理.如果在测试中没有引用此脚本,则此代理将是未定义的.
我假设您在运行Jasmine测试时没有运行SignalR服务器.如果是这种情况,您有两种选择:
>您只需将SignalR在“〜/ signalr / hubs”生成的脚本复制到文件中并在测试中引用该文件即可.您可以通过将浏览器指向生成的脚本URL来手动执行此操作,但是您必须在集线器更改时随时更新此文件.您可以通过运行signalr.exe ghp / path:[包含您的Hub类的.dll的路径]作为后期构建步骤来生成此文件.
>您可以完全避免使用生成的代理.查看SignalR JS API reference的“没有生成的代理”部分.