Unit test instances in angularjs

  • 2020-03-30 04:29:13
  • OfStack

When the ng project is getting larger and larger, unit testing will be put on the agenda. Sometimes the team will put the test first, and some will implement the function first and then test the function module. This has its own advantages and disadvantages.

What is the Karma

It is recommended to use the --save-dev parameter to install and test the relevant NPM module, because this is development related, the following two NPM commands are required for the normal karma run


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

Some commonly used modules will be installed automatically when karma is installed. Refer to the peerDependencies attribute of the package.json file in karma code


 "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"
  }

Then, a typical running framework usually requires a configuration file, which can be a karma. Conf.js in karma, and the code is nodejs style. A common example is as follows:


module.exports = function(config){
  config.set({
    //The following files in the basic directory
    basePath : '../',
    //The test environment needs to load JS information
    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'
    ],
    //Automatically run test
to see if the above file is automatically listened for changes     autoWatch : true,
    //The applied test framework
    frameworks: ['jasmine'],
    //What environment to test the code, in this case, chrome '
    browsers : ['Chrome'],
    //Plugins, such as chrome and jasmine
    plugins : [
            'karma-chrome-launcher',
            'karma-firefox-launcher',
            'karma-jasmine',
            'karma-junit-reporter'
            ],
    //The module name for the output and export of the test content is
    reporters: ['progress', 'junit'],
    //Set the output test content file information
    junitReporter : {
      outputFile: 'test_out/unit.xml',
      suite: 'unit'
    }   });
};

To note here that the above most don't need a separate plug-in installation, for installation when the karma has been installed, there is only the karma - junit - reporter export plug-in requires a separate installation, want to know more information about the configuration file can be, (link: http://karma-runner.github.io/0.12/config/configuration-file.html)

The karma at this point, we want more information about it, (link: http://karma-runner.github.io/)

What is the jasmine

Jasmine is an 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 the explanation of jasmine in the official documents, and the following is a simple translation in Chinese

Jasmine is a behavior driven development test framework that does not rely on any js framework or dom, and is a very clean and friendly API for testing libraries.

Here is a simple example of how to use it

Define a test file command as test.js


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 example from the website, here only several important API, said the more usage, please (link: http://jasmine.github.io/1.3/introduction.html)

1. First of all, any test case is defined by describe function, which has two parameters. The first parameter 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

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

4. BeforeEach and afterEach are mainly used to do things before and after a test task. The above example is to change the value of a variable before execution and then reset the value of the variable after execution

Finally, the scope in the describe function is accessible in its child functions just as it is in the foo variable

To run the above test example, you can use karar to run the following command:


karma start test/karma.conf.js

Next we focus on the controller, instruction, service module unit test in ng.

Unit tests for NG

Because of the ng framework itself, modules are loaded and instantiated by di, so in order to facilitate jasmine to write test scripts, an angula-mock. js test tool class is officially provided to provide module definition, load, injection, and so on.

Here are some common methods in ng-mock

This method is also in the window namespace, very convenient to call

The 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('myApp.filters')); beforeEach(module(function($provide) {
      $provide.value('version', 'TEST_VER');
}));

It is generally used in the beforeEach method, as this ensures that the inject method will get the module configuration when the test task is executed

Angular. Mock. Inject this method is also in the window namespace, very convenient to call

Inject is used to inject ng module configured above, and the aspect is called in the test function of it. Common examples of invocations are 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');
      });
    });
  });

Above are some inject examples provided by the government, the code is very easy to understand, in fact, inject is a built-in dependency injection instance created by angular. Inject method, and then the module injection is the same as the dependency processing in the ordinary ng module

After a brief introduction to ng-mock, let's write a simple unit test with controllers, instructions, and filters.

Unit test of controller in ng

Define a simple controller


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

Then we write a test script


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

We use the $rootScope above to create a subscope, and then pass this parameter into the controller's build method, $controller, which will eventually execute the method in the controller above, and then we check the number of arrays in the subscope and whether the string variable is equal to the expected value.

Want to know more information about the controller in the ng, can (link: https://docs.angularjs.org/guide/controller)

Unit test of instructions in ng

Define a simple instruction


var app = angular.module('myApp', []); app.directive('aGreatEye', function () {
    return {
        restrict: 'E',
        replace: true,
        template: '<h1>lidless, wreathed in flame, 1 times</h1>'
    };
});

Then we write a simple test script


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("<a-great-eye></a-great-eye>")($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");
    });
});

The above example comes from an official source, and eventually the above directive will be used in HTML


<a-great-eye></a-great-eye>

The test script first injects $compile and $rootScope two services, one to compile HTML, one to create scope, notice here _, the default ng injected before and after the service added _, will be ng processing, the two services are saved in the two internal variables, so that the following test case can be called

The $compile method passes in the original command HTML, then passes in $rootScope in the returned function. This completes the binding of the scope to the view, and finally calls $rootScope

Then get the HTML content of the element corresponding to the current instruction and compare it with the expected value.

Want to know more information about the instruction in the ng, can (link: https://code.angularjs.org/1.2.21/docs/guide/directive)

Filter unit test in ng

Define a simple filter


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

Then write a simple test script

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 Filter configuration module, then define a version value, because interpolate depend on the service, with inject into finally interpolate Filter, Filter back note here add Filter suffix, finally the incoming text to the Filter function, compared with expectations.

conclusion

Using tests to develop NG has a lot of benefits, can ensure the stability of the module, there is a point is to be able to in-depth understanding of the internal operation mechanism of NG, so it is recommended to use NG development students to make up for the test!


Related articles: