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
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
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:
});
};
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
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:
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
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:
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里控制器的单元测试
定义一个简单的控制器
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() {
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里指令的单元测试
定义一个简单的指令
app.directive('aGreatEye', function () {
return {
restrict: 'E',
replace: true,
template: '
然后我们编写一个简单的测试脚本
// 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("
// 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里的过滤器单元测试
定义一个简单的过滤器
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!