我刚刚跳到另一个项目,并且基本上,我被要求编写单元测试。因为我已经了解Protractor的e2e测试,所以我现在切换到Karma和Jasmine进行单元测试。我已经下载了业力,茉莉花,业力茉莉花和业力铬发射器。我也安装了角angular,所以应该准备开始了。我已经在互联网上阅读了很多东西,但是现在,我真正需要的是一个真实应用程序的具体示例,以弄清楚如何开始编写测试。我不需要简单的示例,但需要具体的示例和完整的说明。书籍和有用的链接也受到赞赏。预先感谢您的帮助/时间。
describe('ServiceBeingTested Name', (): void => { var mockFirstDependency; var mockSecondDependency; var TestedService; //Mock all dependencies beforeEach((): void => { angular.mock.module('moduleServiceIsIn'); //Register the module which the service is in mockFirstDependency = sinon.stub(new MockFirstDependency());//Sinon if useful for mocking mockSecondDependency = sinon.stub(new MockSecondDependency()); angular.mock.module(($provide): void => { $provide.value('FirstDependency', mockFirstDependency); $provide.value('SecondDependency', mockSecondDependency); }); }); beforeEach(inject( ['TestedService', (_TestedService_: TestedService): void => { TestedService = _TestedService_; }])); //Describe each method in the service describe('method to test', (): void => { it("should...", () => { //testing goes in here expect(TestedService.someMethod()).toBe("some value"); }); });
这是如何测试角度服务的简单示例。在这种情况下,该服务称为TestedService。
您会看到的第一件事是三个变量声明。声明前两个以模拟出此服务的两个依赖关系(假定此服务具有两个依赖关系)。最后一个变量声明将分配给正在测试的实际服务。
现在在beforeEach中:
angular.mock.module
此行注册您要测试服务所在的模块。此行非常重要。
接下来的两行使用Sinon.js来模拟正在测试的服务的依赖关系。我建议研究Sinon.js
它的工作方式是我们有一个名为“ FirstDependency”的依赖项,我创建了一个存根并称为“ MockedFirstDependency”,在这里我创建了它的一个实例。
现在为下一部分(包括$ provide的部分)
$provide.value('FirstDependency', mockFirstDependency);
上面的代码行告诉Angular,每次使用FirstDependency服务时,请改用嘲笑FirstDependency。
现在,在下一个beforeEach之前,我要做的就是注入要测试的实际服务,并将其分配给全局变量。
然后让测试开始
编辑:测试控制器
describe('mainCtrl', (): void => { var $controllerConstructor; var MainCtrlInstance; var mockScope; var mockState; var mockStates; var mockGlobalData; beforeEach(() => { angular.mock.module('mainCtrlModule'); mockScope = sinon.stub(new MockScope()); mockState = sinon.stub(new MockState()); mockStates = sinon.stub(new MockState()); mockGlobalData = sinon.stub(new MockGlobalData()); inject(($controller: ng.IControllerService): void => { $controllerConstructor = $controller; }); //Constructs the controller, all dependencies must be injected here MainCtrlInstance = $controllerConstructor('mainCtrl', { '$Scope': mockScope, '$State': mockState, 'States': mockStates, 'srvGlobalData': mockGlobalData } ); }); describe('Method to Tests', (): void => { it("should...", (): void => { //Testing Begins expect(MainCtrlInstance.method()).toBe("some value"); }); }); });
编辑:测试指令
首先,你需要安装Html2JsPreprocessor用这个命令: NPM安装卡玛- NG-html2js预处理器–save-dev的 作为说这里。
karma.conf.js
files: [ //Obviously include all of your Angular files //but make sure to include your jQuery before angular.js "directory/to/html/directive.html", // include html for directive "directive.js" // file directive is contained in "directive.spec.js"" // spec file ] // include the directive html file to be preprocessed preprocessors: { 'directory/to/html/directive.html': 'ng-html2js' }, plugins : [ 'karma-chrome-launcher', 'karma-jasmine', 'karma-ng-html2js-preprocessor' //include as a plugin too ], ngHtml2JsPreprocessor: { //this part has a lot of useful features but unfortunately I //never got them to work, Google if you need help },
指令
export class myDirectiveController { constructor(/*dependencies for controller*/) { //initializations } //other methods for directive class } export class myDirective implements ng.IDirective { constructor(/*dependencies for directive*/) { } static instance(/*dependencies*/): ng.IDirective { return new myDirective(/*dependencies for directive*/); } restrict = 'E'; templateUrl = 'myDirective.html'; controller = myDirectiveController; controllerAs = 'myDirectiveController'; scope: {}; } angular .module('myDirectiveModule') .directive('myDirective', myDirective.instance);
myDirective.spec.js
describe("myDirective", () => { //do you variable declarations but I'm leaving them out for simplicity beforeEach(() => { angular.mock.module( 'myDirectiveModule', //and other modules in use 'directory/to/html/directive.html' //include directive html as a module ) // now do your mock dependencies as you did with services mockDependency = sinon.stub(new MockDependency()); angular.mock.module(($provide): void => { $provide.value('dependency', mockDependency); } //inject $compile and $rootScope inject(($compile, $rootScope) => { scope = $rootScope.$new(); // your directive gets compiled here element = angular.element("<my-directive></my-directive>"); $compile(element)(scope); $rootScope.$digest(); directiveController = element.controller('myDirective'); //this is your directive's name defined in .directive("myDirective", ...) }); } describe("simple test", () => { it("should click a link", () => { var a = element.find("a"); a.triggerHandler('click'); //very important to call scope.$digest every you change anything in the view or the model scope.$digest(); expect('whatever').toBe('whatever'); }); }); }
早些时候,当我说要在Angular之前包含jQuery文件时,要这样做是因为angular.element()会生成一个jQuery对象,可以在上面使用jQuery API,但是如果不首先包含jQuery,则可以使用angular.element()返回一个jQLite对象,其中包含较少的方法。
调用scope。$ digest()也很重要,因为这将更新指令的绑定。