Angular.js Automation Test Detailed _angularjs

Source: Internet
Author: User
Tags assert set background

This article focuses on the testing part of Ng, mainly includes the following three aspects:

    1. Selection of frames (Karma+jasmine)
    2. Classification and selection of tests (unit Test + end-to-end test)
    3. How each module in NG writes test cases

The following sections are described in detail.

Classification of tests

In the test, generally divided into unit test and end-to-end testing, unit testing is to ensure that the developer to verify the validity of a certain part of the technology, End-to-end (E2E) is when you want to ensure that a bunch of components can be expected to run in the way of use.

Unit tests are divided into two categories: TDD (test-driven development) and BDD (behavior-driven development).

Two development patterns are highlighted below.

TDD (test-driven Development test-driven development) is the use of test cases to drive your software development.

If we want to delve more deeply into TDD, we can divide it into five different phases:

    1. First, the developer writes some test methods.
    2. Second, developers use these tests, but obviously the tests don't pass because the code that has not yet written these features is actually executing.
    3. Next, the developer implements the code in the test.
    4. If the developer writes good code, the next stage will see his test pass.
    5. Then the developer can refactor their code, add comments, make it neat, and the developer knows that if the newly added code destroys something, the test will remind him of the failure.

The flowchart is as follows:


Tdd

Benefits of TDD:

    1. Can drive the system to the final implementation code, can be covered by the test code, that is, "every line of code can be measured."
    2. Test code as the correct guidance to implement the code, eventually evolved into the correct system behavior, can make the entire development process more efficient.

BDD is (behavioral-driven Development Behavior-driven Development) that you should not write tests on the implementation details of your code, but rather write tests against the behavior. BDD tests behavior, which is how the software should work.

    1. Compared to TDD, BDD requires us to write behavioral specifications (functional details) in software development. Feature details and tests look very similar, but the functional details are more subtle. BDD takes a more detailed approach and makes it look like a sentence.
    2. BDD testing should focus on functionality rather than actual results. You'll often hear that BDD is about helping design software, not testing software like TDD.

Final Summary: Iterative verification of TDD is the guarantee of agile development, but there is no clear way to generate tests based on design and to guarantee the quality of test cases, and BDD advocates the idea of using concise natural language to describe system behavior, which compensates for the accuracy of test cases (i.e. system behavior).

Test Framework Selection

Use Karma and Jasmine for unit testing of NG modules.

Karma: Is a node.js based JavaScript test execution Process management tool, a powerful feature of this test tool is that it can monitor (Watch) file changes, and then execute it on its own, showing test results through Console.log.

Jasmine is a test framework for behavioral-driven Development (BDD) that does not rely on any JS framework and DOM, and is a very clean and friendly API test library.

Karma

Karma is a unit Test operating control framework that provides a variety of environments to run unit tests, such as CHROME,FIRFOX,PHANTOMJS, test framework support Jasmine,mocha,qunit, is a nodejs environment for the NPM module.

Karma builds from scratch, eliminating the burden of setting tests and concentrating on application logic. Creates a browser instance, runs the tests against different browsers, and can provide a real-time feedback of the test's operation, providing a debug report.

Tests also rely on some karma plug-ins, such as test coverage karma-coverage tools, karman-fixture tools, and karma-coffee processing tools. In addition, the front-end community to provide a richer plug-in, common testing requirements can be covered.

Installing the test-related NPM module recommends using the--save-dev parameter, since this is a development-related, generic run Karma only requires the following two NPM commands:

NPM Install Karma--save-dev
npm install Karma-junit-reporter--save-dev

Then a typical running framework usually requires a configuration file, in the Karma can be a karma.conf.js, the inside of the code is a Nodejs style, a common example is as follows:

Module.exports = function (config) {
 config.set ({
 //below) the underlying directory in Files
 basepath: '. /',/
 //test environment needs to load the 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 '
 ],
 //whether to automatically monitor the changes in the above file automatically run test
 autowatch:true,
 //Application Test Framework
 Frameworks: [' Jasmine '],
 //with what environment to test the code, here is the Chrome '
 browsers: [' Chrome '],//
 use of Plug-ins, For example, Chrome browser and Jasmine plugin
 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 output of the test content file
 junitreporter: {
 outputfile: ' Test_out/unit.xml ',
 Suite: ' Unit '
 }
 });
};

Run-time Input:

Karma Start Test/karma.conf.js

Jasmine

Jasmine is a test framework for behavioral-driven development that does not rely on any JS framework and DOM, and is a very clean and friendly API test library.

The following is illustrated with a concrete example 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);
 });
    1. First, any test case is defined as a describe function, it has two parameters, the first is used to describe the central content of the test, and the second parameter is a function that writes some real test code.
    2. It is used to define a single specific test task, there are two parameters, the first to describe the test content, the second parameter is a function, which contains some test methods
    3. Expect is used primarily to compute the value of a variable or an expression, and then to compare it to the desired value or to do some other event.
    4. Beforeeach and Aftereach are mainly used to do things before and after the test task, the example of which is to change the value of the variable before execution, and then reset the value of the variable after the execution is complete

Start Unit Test

The following four sections of the controller, instructions, filters, and services are used to write related unit tests. Project address is angular-seed (point me) project, you can download demo and run its test cases.

Demo is a simple Todo application that contains a text entry box that can write notes and press the button to add new notes to the list of notes, using the Notesfactory package Localstorage to store your notes.

Let's introduce the component angular-mocks in the angular test.

About Angular-mocks

In angular, modules are loaded and instantiated through dependency injection, so the official Angular-mocks.js test tool is provided to provide module definition, loading, and dependency injection functions.

Some of these methods are commonly used (mounted under the window namespace):

angular.mock.module: moduleUsed to load existing modules and configure the Inject method injection module information. The specific use is as follows:

Beforeeach (module (' Myapp.filters '));
Beforeeach (Module (function ($provide) {
 $provide. Value (' Version ', ' Test_ver ');
});

This method is generally used in Beforeeach, and the configuration of the module can be obtained before the test case is executed.

angular.mock.inject: injectUsed to inject the configured NG module for the test case to invoke. The specific use is as follows:

It (' should provide a version ', inject (function (mode, version) {
 expect (version). Toequal (' v1.0.1 ');
 Expect (mode) toequal (' app ');
 });

In fact, the inject inside is a built-in dependency injection instance created using the Angular.inject method, and the inside module is the same as the dependency processing of the normal NG module.

Controller part

The angular module is Todoapp, the controller is Todocontroller, and when the button is clicked, the Todocontroller createNote() function is invoked. Here is the code section of App.js.

var Todoapp = angular.module (' Todoapp ', []);
Todoapp.controller (' Todocontroller ', function ($scope, notesfactory) {
 $scope. Notes = Notesfactory.get ();
 $scope. createnote = function () {
 notesfactory.put ($scope. Note);
 $scope. note= ';
 $scope. Notes = Notesfactory.get ();
 }
});
Todoapp.factory (' Notesfactory ', function () {return
 {
 put:function (note) { 
 Localstorage.setitem (' Todo ' + (Object.keys (localstorage). length + 1), note);
 },
 get:function () {
 var notes = [];
 var keys = Object.keys (localstorage);
 for (var i = 0; i < keys.length i++) {
  Notes.push (Localstorage.getitem (keys[i));
 }
 return notes;};
});

In Todocontroller, a service called notesfactory is used to store and extract notes. When Createnote () is invoked, the service is used to deposit a message in localstorage, and then empty the current note. Therefore, in the writing test module is, should ensure that the controller initialization, scope has a certain number of notes, createNote() after the call, the number of notes should be added one.

The specific unit tests are as follows:

 describe (' Todocontroller Test ', function () {Beforeeach (module (' Todoapp '));//will be in all it ( Run before//We don't need a real factory here.
 So we use a fake factory.
 var mockservice = {notes: [' note1 ', ' note2 '],//Only initialize two items get:function () {return this.notes;
 }, Put:function (content) {This.notes.push (content);
 }
 }; Now is the real thing to test spec it (' should return notes array with two elements initially and then add one ', inject (function ($rootSco
 PE, $controller) {//inject dependent project var scope = $rootScope. $new ();
 When creating the controller, we also inject the dependent item var ctrl = $controller (' Todocontroller ', {$scope: scope, notesfactory:mockservice});
 The initialization technology should be 2 expect (scope.notes.length). Tobe (2);
 Enter a new Item scope.note = ' Test3 '; Now run's function that is adds a new note (the "result of hitting" button in HTML)//is running this functions, and it will add to the scope of the additional Notes item.
 Createnote ();
 Look forward to the current number of notes is 3 expect (scope.notes.length). Tobe (3);
})
 ); 
});

In Beforeeach, the module needs to be loaded before each test case is executed module("todoApp") .

Since there is no need for external, so we build a fake mockservice locally instead of factory, to simulate Notefactory, which contains the same functions, get() and put() . This fake factory loads the data from the array instead of the localstorage operation.

In it, a dependent project is declared $rootScope and $controller can be automatically injected by angular, which is $rootScope used to get the root scope to be $controller used as a new controller to create.

$controllerThe service requires two parameters. The first parameter is the name of the controller that will be created. The second parameter is an object that represents a controller-dependent project.
$rootScope.$new()method returns a new scope that is used to inject the controller. At the same time we passed Mockservice as false factory.
The initialization then predicts the number of notes based on the length of the notes array and, after the function is executed createNote() , changes the length of the array so that two test cases can be written.

Factory part

The unit test code for the factory section is as follows:

Describe (' notesfactory tests ', function () {var factory;
 Run the Beforeeach (function () {//Load Modules module (' Todoapp ') before all it functions;
 Inject your factory service inject (function (notesfactory) {factory = Notesfactory;
 });
 var store = {todo1: ' test1 ', Todo2: ' Test2 ', Todo3: ' Test3 '};
 Spyon (localstorage, ' GetItem '). Andcallfake (function (key) {return store[key];
 });
 Spyon (localstorage, ' SetItem '). Andcallfake (function (key, value) {return Store[key] = value + ';
 });
 Spyon (Localstorage, ' clear '). Andcallfake (function () {store = {};
 });
 Spyon (Object, ' Keys '). Andcallfake (function (value) {var keys=[];
 for (var key in store) {Keys.push (key);
 return keys;
 });
 });
 Check to see if we have the function it wants (' should have a Get function ', function () {Expect (angular.isfunction (Factory.get)). Tobe (True);
 Expect (Angular.isfunction (factory.put)). Tobe (True);
 });
 Check to see if 3 records are returned it (' should return three Todo notes initially ', function () {var result = Factory.get ();
 Expect (result.length). Tobe (3);
 }); // Check to see if a new record is added it (' should return four TODO notes after adding one more ', function () {factory.put (' angular is awesome ');
 var result = Factory.get ();
 Expect (result.length). Tobe (4);
}); });

In the Todocontroller module, the actual factory will invoke Localstorage to store and extract the items of the notes, but since we do not need to rely on external services to acquire and store the data in our unit tests, we need to localStorage.getItem() localStorage.setItem() perform a spy operation , that is, the use of false functions to replace these two parts.

spyOn(localStorage,'setItem')andCallFake()is used to monitor with a false function. The first parameter specifies the object to listen to, the second parameter specifies the function to listen to, and then andcallfake the API to write its own function. As a result, a rewrite of Localstorage and object is done in the test so that the function can return the values in our own array.

In a test case, first detect if the newly encapsulated factory function contains get() and put() both methods, and then factory.put() assert the number of notes after the operation.

Filter section

We add a filter. The TRUNCATE function is to intercept the first 10 digits if the incoming string is too long. The source code is as follows:

Todoapp.filter (' Truncate ', function () {return
 function (input,length) {return
 (input.length > length?) Input.substring (0,length): input);
 }
);

So in unit tests, you can assert the length of a substring based on the condition of the passed-in string.

Describe (' Filter test ', function () {
 Beforeeach (' Todoapp '));
 It (' should truncate the input to 1o characters ', inject (function (truncatefilter) {
 expect (truncatefilter) (' Abcdefghijkl ',). Length). Tobe (a);});;
});

The assertion has been discussed before, and it is worth noting that we need to add filter to the name after the call, and then call it normally.

Directive part

The directive part of the source code:

Todoapp.directive (' Customcolor ', function () {return
 {
 restrict: ' A ',
 link:function (scope, Elem, Attrs) {
 elem.css ({' Background-color ': Attrs.customcolor});
 }
 };

Since the instruction must be compiled before the associated template can be generated, we will introduce the $compile service to complete the actual compilation and then test the elements that we want to test.

angular.element()Creates a jqlite element, and then we compile it into a newly generated self scope, and we can be tested. The specific test cases are as follows:

Describe (' directive tests ', function () {
 Beforeeach (module (' Todoapp '));
 It (' should set background to RGB (128, 128, 128) ',
 inject (function ($compile, $rootScope) {
 scope = $rootScope. $ New ();
 Get an element
 Elem = angular.element ("<span custom-color=\" RGB (128, 128, 128) \ ">sample</span>");
 Creates a new scope of the scope
 = $rootScope. $new ();
 Finally compile the HTML
 $compile (elem) (scope);
 Want the background color of the element to be as expect as we think (
 elem.css ("Background-color")). Toequal (' RGB (128, 128, 128) ');})
;

Start End-to-end Testing

In End-to-end testing, we need to do black-box testing from the user's point of view, so there are some dom operations involved. Combine a pair of components and check to see if the results are as expected.
In this demo, we simulate the user input information and press the button process, detection information can be added to the localstorage.

In the E2E test, you need to introduce Angular-scenario this file, and create an HTML as a run of the show, in the HTML containing the E2E test code of the execution JS file, after writing the test, run the HTML file to view the results. The specific e2e code is as follows:

Describe (' My app ', function () {
 Beforeeach (function () {
 browser (). NavigateTo (). /.. /app/notes.html ');
 var oldcount =-1;
 It ("Entering and performing click", Function () {
 element (' ul '). Query (function ($el, done) {
 Oldcount = $ El.children (). length;
 Done ();
 });
 Input (' note '). Enter (' test data ');
 Element (' button '). Query (function ($el, done) {
 $el. Click ();
 Done ();
 });
 It (' should add one more element now ', function () {
 expect (repeater (' ul Li '). Count ()). Tobe (Oldcount + 1);
 }); 
});

In the End-to-end testing process, we first navigate to our main HTML page app/notes.html, which can be done by browser.navigateTo() element.query() selecting the UL element and recording how many of the initialized items are stored in the Oldcount variable.

Then input('note').enter() , type a new note, and then simulate a click to check if a new note (LI Element) has been added. You can then use assertions to compare the number of new and old notes.

Summarize

The above is the entire content of this article, I hope the content of this article for everyone's study or work can bring certain help, if you have questions you can message exchange.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.