-2

Angular Unit Testing

I Unit testing

I.1. Khái niệm

  • Unit Tets là kỹ thuật kiểm nghiệm các hoạt động của của mã code giúp phát hiện sai sót kịp thời. Unit Test còn có thể giúp phát hiện các vấn đề tiềm ẩn và các lỗi thời gian thực ngay cả trước khi QA tìm ra, thậm chí có thể sửa lỗi ngay từ ý tưởng thiết kế.

  • Unit Test là các đoạn mã có cấu trúc giống như các đối tượng được xây dựng để kiểm tra từng bộ phận trong hệ thống. Mỗi Unit Test sẽ gửi đi một thông điệp và kiểm tra câu trả lời nhận được đúng hay không, bao gồm: Các kết quả trả về mong muốn, các lỗi ngoại lệ mong muốn. Các đoạn mã Unit Test hoạt động liên tục hoặc định kỳ để thăm dò và phát hiện các lỗi kỹ thuật trong suốt quá trình phát triển, do đó Unit Test còn được gọi là kỹ thuật kiểm nghiệm tự động.

I.2. Các đặc điểm của Unit Test

  • Đóng vai trò như những người sử dụng đầu tiên của hệ thống.
  • Chỉ có giá trị khi chúng có thể phát hiện các vấn đề tiềm ẩn hoặc lỗi kỹ thuật.
  • Giảm thiểu các rủi ro khi phát triển feature mới hay giảm thiểu bug trong quá trình thay đổi các chức năng có sẵn
  • Cải thiện thiết kế và cho phép refactoring code tốt hơn.

I.3. Vòng đời của Unit Test

life_cycle.png

II. Unit Test đối với AngularJS

  • Có rất nhiều các framework, tool test hỗ trợ cho Angular điển hình như: Karma, Jasmine, angular-mocks

II.1 Karma

  • Karma là một Javascript tool được sử dụng để load ứng dụng và thực thi test của bạn. Karma sẽ được thực thi bằng dòng lệnh và sẽ hiển thị kết quả cho bạn biết mỗi khi bạn chạy trình duyệt.
  • Karma được viết bằng NoteJS và nó phải được cài thông qua npm

II.2. Jasmine

  • Jasmine là một BDD (behavior driven development framework) cho ứng dụng Javascript. Jasmine là công cụ được chọn nhiều nhất cho việc test ứng dụng Angular. Jasmine cung cấp các tính năng cho phép cấu trúc test cũng như tạo ra assertions.
  • Jamine sử dụng describe để nhóm các function test lại với nhau, cung cấp nhiều các matcher cho phép bạn tạo các assertions.

II.3. angular-mocks

  • angular-mocks là một module ngMock của Anguar, nó cung cấp các kiểu mock cho việc test của bạn.

III. Xây dựng ứng dụng test

III.1. Cài đặt

testing_structure.png

  • Việc cấu hình cho Karma karma.conf.js là rất quan trọng bạn phải cấu hình để karma biết được đâu là code và đâu là spec ..
  • Đây là cấu hình của tôi trong file karma.conf.js

karma_conf.png

III.2. Thực hành

III.2.1. Ví dụ calculator

Js code:

window.Calculator = {
  add: function () {
    var sum = 0;
    for (var i = 0; i < arguments.length; i++) {
      sum += arguments[i]
    }
    return sum;
  }
};

spec:


describe("Calculator", function () {
  describe("when adding function", function () {
    it("should add numbers", function () {
      expect(Calculator.add(4)).toEqual(4);
    });
  });
});

Chạy karma start trên terminal để xem kết quả =>> test pass

Giờ hãy chỉnh sửa một chút về code js: Tính tổng các số truyền vào và đồng thời cộng gộp tổng đó vào những lần tiếp theo

window.Calculator = {
  current: 0,
  add: function () {
    var sum = this.current;
    for (var i = 0; i < arguments.length; i++) {
      sum += arguments[i]
    }
    this.current = sum;
    return this.current;
  }
};

và thử thêm expect vào spec

    it("should add numbers", function () {
      expect(Calculator.add(4)).toEqual(4);
    });

    it("should add numbers", function () {
      expect(Calculator.add(4)).toEqual(4);
    });

kết quả

PhantomJS 2.1.1 (Linux 0.0.0): Executed 3 of 3 (1 FAILED) (0.041 secs / 0.003 secs)

Tại sao lại vậy vì tổng của lần chạy sau bằng tổng của lần chạy trước + thêm biến truyền vào của lần 2 Jasmine cung cấp beforeEach giúp bạn khởi tạo lại các biến cần thiết ( giống như trong Rspec)

    beforeEach(function () {
      Calculator.current = 0;
    })

    it("should add numbers", function () {
      expect(Calculator.add(4)).toEqual(4);
    });

    it("should add numbers", function () {
      expect(Calculator.add(4)).toEqual(4);
    });

Result:

PhantomJS 2.1.1 (Linux 0.0.0): Executed 3 of 3 SUCCESS (0.037 secs / 0.005 secs)

III.2.2. Spec với controller

JS file Canculator.js

  angular.module(app, []);
  angular.module(app).controller('CalController', function CalController($scope) {
    $scope.z = 0;
    $scope.sum = function() {
      $scope.z = $scope.x + $scope.y;
    };
  });
  // load app
  angular.element(document).ready(function() {
    angular.bootstrap(document, [app]);
  });

Spec

describe('calculator', function () {
  beforeEach(angular.mock.module('app'));
  var $controller;
  beforeEach(angular.mock.inject(function(_$controller_){
    $controller = _$controller_;
  }));

  describe('sum', function () {
    it('should return numbers', function () {
      var $scope = {};
      var controller = $controller('CalController', { $scope: $scope });
      $scope.x = 2;
      $scope.y = 2;
      $scope.sum();
      expect($scope.z).toBe(4);
    });
  });
});

Sử dụng ngMock để mock một app beforeEach(angular.mock.module('app')); Mỗi khi app module được khởi tạo, ta sẽ gọi inject funtion để tham chiếu tới controller bằng biến $controller

  beforeEach(angular.mock.inject(function(_$controller_){
    $controller = _$controller_;
  }));

Kết

Bài viết sau sẽ chi tiết hơn về các matcher trong angular, spec với directive …

Source code : https://github.com/khanhhd/testing

Tham khảo:

https://docs.angularjs.org/guide/unit-testing

https://www.smashingmagazine.com


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí