Home >Web Front-end >JS Tutorial >Unit test example in angularjs_AngularJS

Unit test example in angularjs_AngularJS

WBOY
WBOYOriginal
2016-05-16 16:28:531493browse

When the ng project gets bigger and bigger, unit testing will be put on the agenda. Sometimes the team will test first, and some will implement the function first and then test the functional module later. This has its own pros and cons. Today I will mainly talk about Let’s talk about using karma and jasmine to perform unit testing of the ng module.

What is Karma

Karma is a unit test run control framework that provides running unit tests in different environments, such as chrome, firfox, phantomjs, etc. The test framework supports jasmine, mocha, qunit, and is an npm module using nodejs as the environment.

It is recommended to use the ----save-dev parameter to install test-related npm modules, because this is related to development. Generally, to run karma, you only need the following two npm commands

Copy code The code is as follows:

npm install karma --save-dev
npm install karma-junit-reporter --save-dev

When installing karma, some commonly used modules will be automatically installed. Please refer to the peerDependencies attribute of the package.json file in the karma code

Copy code The code is as follows:

"peerDependencies": {
"karma-jasmine": "~0.1.0",
"karma-requirejs": "~0.2.0",
"karma-coffee-preprocessor": "~0.1.0",
"karma-html2js-preprocessor": "~0.1.0",
"karma-chrome-launcher": "~0.1.0",
"karma-firefox-launcher": "~0.1.0",
"karma-phantomjs-launcher": "~0.1.0",
"karma-script-launcher": "~0.1.0"
}

A typical running framework usually requires a configuration file. In karma, it can be a karma.conf.js. The code inside is in nodejs style. A common example is as follows:

Copy code The code is as follows:

module.exports = function(config){
config.set({
//The basic directory in the files below
basePath : '../',
// JS information that needs to be loaded in the test environment
files : [
‘app/bower_components/angular/angular.js’,
       'app/bower_components/angular-route/angular-route.js',
        'app/bower_components/angular-mocks/angular-mocks.js',
'app/js/**/*.js',
      'test/unit/**/*.js'
],
// Whether to automatically monitor changes in the above files and automatically run tests
autoWatch : true,
// Application testing framework
frameworks: ['jasmine'],
//What environment to use to test the code, here is chrome`
browsers: ['Chrome'],
// Plug-ins used, such as chrome browser and jasmine plug-in
plugins : [
             'karma-chrome-launcher',
             'karma-firefox-launcher',
             'karma-jasmine',
            'karma-junit-reporter'
],
// Output of test content and module name for export
Reporters: ['progress', 'junit'],
//Set the information for outputting the test content file
JunitReporter : {
OutputFile: 'test_out/unit.xml',
Suite: 'unit'
}

});
};

It should be noted here that most of the above plug-ins do not need to be installed separately, because they have already been installed when installing karma. Only the karma-junit-reporter export plug-in needs to be installed separately. I want to know more about the configuration. File information is available, Click here

That’s it for karma. If you want to know more about it, Click here

What is jasmine

Jasmine is a behavior-driven development framework for testing JavaScript code. It does not depend on any other JavaScript frameworks. It does not require a DOM. And it has a clean, obvious syntax so that you can easily write tests.

The above is its explanation in the official jasmine documentation. Below is a simple translation in Chinese

Jasmine is a testing framework for behavior-driven development. It does not rely on any js framework or DOM. It is a very clean and API-friendly testing library.

The following is a simple example to illustrate its usage

Define a test file command as test.js

Copy code The code is as follows:

describe("A spec (with setup and tear-down)", function() {
var foo;

beforeEach(function() {
foo = 0;
foo = 1;
});

afterEach(function() {
foo = 0;
});

it("is just a function, so it can contain any code", function() {
Expect(foo).toEqual(1);
});

it("can have more than one expectation", function() {
Expect(foo).toEqual(1);
Expect(true).toEqual(true);
});
});

The above examples are from the official website. Here are just a few important APIs. For more usage, please Click here

1. First, any test case is defined with the describe function, which has two parameters. The first one is used to describe the general central content of the test, and the second parameter is a function in which some real test code is written

2.it is used to define a single specific test task. It also has two parameters. The first one is used to describe the test content, and the second parameter is a function that stores some test methods

3.expect is mainly used to calculate the value of a variable or an expression, and then compare it with the expected value or do some other events

4.beforeEach and afterEach are mainly used to do something before and after executing the test task. The above example is to change the value of the variable before execution, and then reset the value of the variable after the execution is completed

The last thing to say is that the scope in the describe function can be accessed in the sub-functions just like ordinary JS, just like it accesses the foo variable above

If you want to run the above test example, you can run it through karar. The command example is as follows:

Copy code The code is as follows:

karma start test/karma.conf.js

Let’s focus on unit testing of controllers, instructions, and service modules in ng.

NG unit testing

Due to the framework of ng itself, modules are loaded and instantiated through di. Therefore, in order to facilitate the writing of test scripts with jasmine, the official provides a testing tool class of angular-mock.js to provide module definitions. , loading, injection, etc.

Let’s talk about some common methods in ng-mock

1.angular.mock.module This method is also in the window namespace and is very convenient to call

module is used to configure the module information injected by the inject method. The parameters can be strings, functions, and objects, and can be used as follows

Copy code The code is as follows:

beforeEach(module('myApp.filters'));

beforeEach(module(function($provide) {
$provide.value('version', 'TEST_VER');
}));

It is generally used in the beforeEach method, because this can ensure that the inject method can obtain the module configuration when executing the test task

1.angular.mock.inject This method is also in the window namespace and is very convenient to call

inject is used to inject the ng module configured above, which is called in the test function of it. Common calling examples are as follows:

Copy code The code is as follows:

angular.module('myApplicationModule', [])
      .value('mode', 'app')
      .value('version', 'v1.0.1');


  describe('MyApp', function() {

    // You need to load modules that you want to test,
    // it loads only the "ng" module by default.
    beforeEach(module('myApplicationModule'));


    // inject() is used to inject arguments of all given functions
    it('should provide a version', inject(function(mode, version) {
      expect(version).toEqual('v1.0.1');
      expect(mode).toEqual('app');
    }));


    // The inject and module method can also be used inside of the it or beforeEach
    it('should override a version and test the new version is injected', function() {
      // module() takes functions or strings (module aliases)
      module(function($provide) {
        $provide.value('version', 'overridden'); // override version here
      });

      inject(function(version) {
        expect(version).toEqual('overridden');
      });
    });
  });

上面是官方提供的一些inject例子,代码很好看懂,其实inject里面就是利用angular.inject方法创建的一个内置的依赖注入实例,然后里面的模块注入跟普通ng模块里的依赖处理是一样的

简单的介绍完ng-mock之后,下面我们分别以控制器,指令,过滤器来编写一个简单的单元测试.

ng里控制器的单元测试

定义一个简单的控制器

复制代码 代码如下:

var myApp = angular.module('myApp',[]);

    myApp.controller('MyController', function($scope) {
      $scope.spices = [{"name":"pasilla", "spiciness":"mild"},
                       {"name":"jalapeno", "spiciness":"hot hot hot!"},
                       {"name":"habanero", "spiciness":"LAVA HOT!!"}];
      $scope.spice = "hello feenan!";
});

然后我们编写一个测试脚本

复制代码 代码如下:

describe('myController function', function() {

  describe('myController', function() {
    var $scope;

    beforeEach(module('myApp'));

    beforeEach(inject(function($rootScope, $controller) {
      $scope = $rootScope.$new();
      $controller('MyController', {$scope: $scope});
    }));

    it('should create "spices" model with 3 spices', function() {
      expect($scope.spices.length).toBe(3);
    });

    it('should set the default value of spice', function() {
      expect($scope.spice).toBe('hello feenan!');
    });
  });

});

上面利用了$rootScope来创建子作用域,然后把这个参数传进控制器的构建方法$controller里去,最终会执行上面的控制器里的方法,然后我们检查子作用域里的数组数量以及字符串变量是否跟期望的值相等.

想要了解更多关于ng里的控制器的信息,可以点击这里

ng里指令的单元测试

定义一个简单的指令

复制代码 代码如下:

var app = angular.module('myApp', []);

app.directive('aGreatEye', function () {
    return {
        restrict: 'E',
        replace: true,
        template: '

lidless, wreathed in flame, 1 times

'
    };
});

然后我们编写一个简单的测试脚本

复制代码 代码如下:

describe('Unit testing great quotes', function() {
    var $compile;
    var $rootScope;

    // Load the myApp module, which contains the directive
    beforeEach(module('myApp'));

    // Store references to $rootScope and $compile
    // so they are available to all tests in this describe block
    beforeEach(inject(function(_$compile_, _$rootScope_){
      // The injector unwraps the underscores (_) from around the parameter names when matching
      $compile = _$compile_;
      $rootScope = _$rootScope_;
    }));

    it('Replaces the element with the appropriate content', function() {
        // Compile a piece of HTML containing the directive
        var element = $compile("")($rootScope);
        // fire all the watches, so the scope expression 1 will be evaluated
        $rootScope.$digest();
        // Check that the compiled element contains the templated content
        expect(element.html()).toContain("lidless, wreathed in flame, 2 times");
    });
});

上面的例子来自于官方提供的,最终上面的指令将会这用在html里使用

复制代码 代码如下:


测试脚本里首先注入$compile与$rootScope两个服务,一个用来编译html,一个用来创建作用域用,注意这里的_,默认ng里注入的服务前后加上_时,最后会被ng处理掉的,这两个服务保存在内部的两个变量里,方便下面的测试用例能调用到

$compile方法传入原指令html,然后在返回的函数里传入$rootScope,这样就完成了作用域与视图的绑定,最后调用$rootScope.$digest来触发所有监听,保证视图里的模型内容得到更新

然后获取当前指令对应元素的html内容与期望值进行对比.

想要了解更多关于ng里的指令的信息,可以点击这里

ng里的过滤器单元测试

定义一个简单的过滤器

复制代码 代码如下:

var app = angular.module('myApp', []);
app.filter('interpolate', ['version', function(version) {
    return function(text) {
      return String(text).replace(/%VERSION%/mg, version);
    };
  }]);

然后编写一个简单的测试脚本
复制代码 代码如下:

describe('filter', function() {
beforeEach(module('myApp'));


describe('interpolate', function() {

beforeEach(module(function($provide) {
$provide.value('version', 'TEST_VER');
}));


It('should replace VERSION', inject(function(interpolateFilter) {
Expect(interpolateFilter('before %VERSION% after')).toEqual('before TEST_VER after');
}));
});
});

The above code first configures the filter module, then defines a version value, because interpolate relies on this service, and finally uses inject to inject the interpolate filter. Note that the Filter suffix must be added after the filter here, and finally the text content is passed to Executed in the filter function and compared with the expected value.

Summary

There are many benefits to using tests to develop NG. It can ensure the stability of the module. Another point is that it can have an in-depth understanding of the internal operating mechanism of ng. Therefore, it is recommended that students who develop with ng quickly make up for the tests!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn