小编典典

Jasmine,Karma,Angular如何在Angular应用上编写测试?

angularjs

我刚刚跳到另一个项目,并且基本上,我被要求编写单元测试。因为我已经了解Protractor的e2e测试,所以我现在切换到Karma和Jasmine进行单元测试。我已经下载了业力,茉莉花,业力茉莉花和业力铬发射器。我也安装了角angular,所以应该准备开始了。我已经在互联网上阅读了很多东西,但是现在,我真正需要的是一个真实应用程序的具体示例,以弄清楚如何开始编写测试。我不需要简单的示例,但需要具体的示例和完整的说明。书籍和有用的链接也受到赞赏。预先感谢您的帮助/时间。


阅读 214

收藏
2020-07-04

共1个答案

小编典典

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()也很重要,因为这将更新指令的绑定。

2020-07-04