Angularjs Jasmine,Karma,Angular如何在我的Angular应用程序上编写测试?

Angularjs Jasmine,Karma,Angular如何在我的Angular应用程序上编写测试?,angularjs,unit-testing,jasmine,karma-runner,Angularjs,Unit Testing,Jasmine,Karma Runner,我刚刚跳转到另一个项目,基本上,我被要求编写单元测试。因为我已经知道e2e测试的量角器,我现在切换到Karma和Jasmine来执行单元测试。我已经下载了karma、jasmine、karma jasmine和karma chrome启动器。我也安装了角度模拟,所以我应该准备好开始了。我在互联网上读过很多东西,但现在,我真正需要的是一个真实应用程序的具体示例,以了解如何开始编写测试。我不需要简单的例子,但具体的例子和充分的解释。书籍和有用的链接也很受欢迎。提前感谢您的帮助/时间 describe

我刚刚跳转到另一个项目,基本上,我被要求编写单元测试。因为我已经知道e2e测试的量角器,我现在切换到Karma和Jasmine来执行单元测试。我已经下载了karma、jasmine、karma jasmine和karma chrome启动器。我也安装了角度模拟,所以我应该准备好开始了。我在互联网上读过很多东西,但现在,我真正需要的是一个真实应用程序的具体示例,以了解如何开始编写测试。我不需要简单的例子,但具体的例子和充分的解释。书籍和有用的链接也很受欢迎。提前感谢您的帮助/时间

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

您将看到的第一件事是三个变量声明。前两个声明用于模拟此服务的两个依赖项。(假设此服务有两个依赖项)。最后一个变量声明将被分配给正在测试的实际服务

现在在前面的步骤中:

angular.mock.module
此行注册您正在测试的服务所在的模块。这条线很重要

接下来的两行使用Sinon.js模拟被测试服务的依赖关系。我建议您查看Sinon.js

它的工作方式是我们有一个称为“FirstDependency”的依赖项,我创建了它的存根,称为“MockedFirstDependency”,在这里我创建了它的一个实例

现在进入下一部分(包括$PROFECT的部分)

上面这一行的作用是告诉Angular,每次使用FirstDependency服务时,都使用mockFirstDependency

现在在下一篇文章中,我所做的就是注入我正在测试的实际服务,并将其分配给我的全局变量

然后让测试开始

编辑:测试控制器

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");
        });
    });
});
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);
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');
        });

    });
}
编辑:测试指令

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");
        });
    });
});
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);
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');
        });

    });
}
首先,您需要使用以下命令安装html2js预处理器:npm install karma-ng-html2js-preprocessor——保存dev

karma.conf.js

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");
        });
    });
});
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);
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');
        });

    });
}
指令.js

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");
        });
    });
});
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);
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');
        });

    });
}
myDirective.spec.js

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");
        });
    });
});
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);
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');
        });

    });
}
description(“我的指令”),()=>{
//您是否需要变量声明,但为了简单起见,我将省略它们
在每个之前(()=>{
角模(
“myDirectiveModule”、//和其他正在使用的模块
'directory/to/html/directive.html'
//将指令html包含为一个模块
)
//现在,像处理服务一样处理模拟依赖项
mockDependency=sinon.stub(新的mockDependency());
angular.mock.module($provide):void=>{
$provide.value('dependency',mockDependency);
}
//注入$compile和$rootScope
注入($compile,$rootScope)=>{
scope=$rootScope.$new();
//您的指令在这里编译
元素=角度。元素(“”);
$compile(元素)(范围);
$rootScope.$digest();
directiveController=element.controller('myDirective');//这是在.directive(“myDirective”,…)中定义的指令名称
});
}
描述(“简单测试”,()=>{
它(“应该点击链接”,()=>{
var a=元素。查找(“a”);
a、 triggerHandler('click');
//调用scope非常重要。$digest每次更改视图或模型中的任何内容
范围。$digest();
期望(“任何”)。托比(“任何”);
});
});
}
前面我说过在创建Angular之前包含jQuery文件,之所以这样做是因为Angular.element()将生成一个jQuery对象,您可以在该对象上使用jQuery API,但是如果不首先包含jQuery,那么Angular.element()将返回一个包含较少方法的jQLite对象


调用scope.$digest()也很重要,因为它会更新指令的绑定。

以下是一些提示和技巧,可以帮助您了解“hello world”示例。这也是一个很好的教程@Amy,非常感谢。有更多依赖项的控制器呢?假设我有一个类似模块的控制器呢?有更多依赖项的控制器呢?假设我有一个类似模块:'angular.module(“main”),[]).controller(“mainCtrl”,function($scope,$state,States,srvGlobalData){if(!srvGlobalData.userData.loggedUser)$state.go(States.login);}).directive('main',function(){return{restrict:'E',controller:'mainCtrl',templateUrl:'url…'}});'你说:“:void=>”,“=>”?”是什么意思?我不明白。谢谢advance@Mar3,抱歉,这是TypeScript,JavaScript等价物是…function(){}例如,($compile)=>{}相当于函数($compile){}和about void,这只是返回类型,可以忽略'description('Test a controller',function(){var$scope,ctrl,$state;//services to mock var StatesMock,srvGlobalDataMock;beforeach(function(){module('main');inject(function))($rootScope,$controller,$state,srvGlobalData){$scope=$rootScope.$new();ctrl=$controller('geiatCtrl',{$scope:$scope,$state:$state,States:geiatStatesMock,srvGlobalData:srvGlobalDataMock});});它('should load',function(){expect(ctrl).toBeDefined();});});'