เริ่มต้นเขียน unit test กับ JavaScript AngularJS ตอนที่ 2 unit test service

ในบทความที่ผ่านมา เราได้เรียนรู้วิธีการติดตั้งเครื่องมือที่จำเป็นในการเขียน unit test และคำสั่ง JavaScript unit test แบบง่ายๆ โดยใช้ Jasmine และ Karma

ในตอนนี้เราจะได้มาเริ่มเขียน unit test จริงๆ กับ AngularJS project กันแล้ว

ขั้นตอนต่างๆ เป็นดังนี้

  • เพิ่ม AngularJS framework เข้าไปใน project
  • สร้าง AngularJS Service ง่ายๆ ขึ้นมา
  • เตรียม unit test ไว้ใช้ทดสอบการทำงานของ AngularJS service
  • ใช้งาน AngularJS mock module
  • ทดสอบการทำงาน run npm test

เพิ่ม AngularJS framework เข้าไปใน project

เข้าไปที่ root ของ project แล้วสร้าง folder ใหม่ชื่อว่า lib

จากนั้นให้เรา download AngularJS จาก https://angularjs.org/ unzip แล้ว copy folder angular-1.x.x เข้าไปวางใน folder lib จะได้โครงสร้างของ project เป็นดังนี้

image 1

แก้ไข karma.conf.js เพิ่ม JavaScript file ที่จำเป็นเพื่อใช้สำหรับ AngularJS project

karma.conf.js

// Karma configuration
// Generated on Sat Feb 13 2016 11:28:56 GMT+0700 (SE Asia Standard Time)

module.exports = function(config) {
  config.set({

    // base path that will be used to resolve all patterns (eg. files, exclude)
    basePath: '',


    // frameworks to use
    // available frameworks: https://npmjs.org/browse/keyword/karma-adapter
    frameworks: ['jasmine'],


    // list of files / patterns to load in the browser
    files: [
      'lib/angular-1.5.0/angular.min.js',
      'lib/angular-1.5.0/angular-mocks.js',
      'src/**/*.js',
      'spec/**/*.js'
    ],


    // list of files to exclude
    exclude: [
    ],


    // preprocess matching files before serving them to the browser
    // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
    preprocessors: {
    },


    // test results reporter to use
    // possible values: 'dots', 'progress'
    // available reporters: https://npmjs.org/browse/keyword/karma-reporter
    reporters: ['progress'],


    // web server port
    port: 9876,


    // enable / disable colors in the output (reporters and logs)
    colors: true,


    // level of logging
    // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
    logLevel: config.LOG_INFO,


    // enable / disable watching file and executing tests whenever any file changes
    autoWatch: true,


    // start these browsers
    // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
    browsers: ['PhantomJS'],


    // Continuous Integration mode
    // if true, Karma captures browsers, runs the tests and exits
    singleRun: false,

    // Concurrency level
    // how many browser should be started simultaneous
    concurrency: Infinity
  })
}

บรรทัดที่ 18 และ 19 เราได้เพิ่ม 'lib/angular-1.5.0/angular.min.js', 'lib/angular-1.5.0/angular-mocks.js' ตามลำดับ

  • angular.min.js เป็น JavaScript file หลักเพื่อใช้ใน AngularJS project
  • angular-mocks.js เพื่อใช้ angular.mock module สำหรับ unit test

สร้าง AngularJS Service ง่ายๆ ขึ้นมา

ให้เราสร้าง JavaScript file ใหม่ขึ้นมาใน folder src ตั้งชื่อว่า weatherApp.js แก้ไข file เป็นดังนี้

src/weatherApp.js

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

app.factory('weatherService', function () {
    var service = {};

    service.getWeathers = function () {
        var cities = [
            {'name': 'Bangkok', 'temp': 32},
            {'name': 'San Francisco', 'temp': 13},
            {'name': 'Los Angeles', 'temp': 14},
            {'name': 'Taipei', 'temp': 21}
        ];
        return cities;
    };

    return service;
});

เตรียม unit test ไว้ใช้ทดสอบการทำงานของ AngularJS service

ให้เราสร้าง JavaScript file ใน folder spec ตั้งชื่อว่า weatherServiceSpec.js แล้วแก้ไข file เป็นดังนี้

spec/weatherServiceSpec.js

describe('weatherService', function () {

    it('getWeathers should return 4 cities', function () {

        var service = '???';
        expect(service.getWeathers().length).toBe(4);
    });
});

จะเห็นได้ว่าตอนนี้ ใน unit test เราต้องการกำหนดค่า weatherService object ให้กับตัวแปร service เพื่อมาใช้ทดสอบว่า เมื่อเรียกใช้ function getWeathers แล้วจะ return Array ที่มีจำนวนสมาชิก 4 ตัว

แต่คำถามคือ เราจะได้ object weatherService มาได้อย่างไร

คำตอบคือ Angular มี mock module ที่ช่วยสร้าง weatherService ให้เรานำไปใช้งานต่อได้เลย

ใช้งาน AngularJS mock module

ขึ้นตอนของการสร้าง weatherService object ขึ้นมาใช้งานใน unit test เป็นดังนี้

  • ใช้ angular.mock.module เพื่อ load module weatherApp ที่มี weatherService อยู่
  • ใช้ angular.mock.inject และส่ง argument ที่มีชื่อตรงกับ Service ที่เราต้องการคือ weatherService เราก็จะได้ weatherService เพื่อใช้งานได้เลย

จากความรู้ตรงนี้ เราสามารถแก้ไข file weatherServiceSpec.js เป็นดังนี้

spec/weatherServiceSpec.js

describe('weatherService', function () {

    it('getWeathers should return 4 cities', function () {

        //load module
        angular.mock.module('weatherApp');

        //get service
        var service = null;
        angular.mock.inject(function (weatherService) { //match argument to existing service in module
            service = weatherService;
        });

        expect(service.getWeathers().length).toBe(4);
    });

});

ทดสอบการทำงานด้วยคำสั่ง run npm test

เปิด Windows command line หรือ Mac Linux terminal แล้วใช้คำสั่งต่อไปนี้

run npm test

ผลลัพธ์การทำงานที่หน้าจอ

image 1

ผลลัพธ์การทำงาน แสดงให้เห็นว่า test weatherService getWeathers ทำงานได้ถูกต้อง return array ที่มีสมาชิก 4 ตัวกลับมา

สังเกตว่า เรามี test ที่ผ่านสอง test cases เนื่องจาก เรามี code เดิมจากบทความที่แล้ว ที่เราได้ทดสอบ add function รวมเข้าไปด้วย

ส่งท้าย

ในบทความนี้ ผมได้ยกตัวอย่างการใช้งาน unit test กับ AngularJS โดยเริ่มจาก AngularJS service ก่อน แทนที่จะกระโดดไป controller เลย เนื่องจากการเขียน unit test ตัว service จะเข้าใจได้ง่ายกว่า controller

โดยอาศัยความเข้าในส่วนนี้ เราก็สามารถนำไปประยุกต์กับ controller ได้โดยจะยกตัวอย่างในบทความต่อไป

มีคำถาม หรือข้อสงสัยใดๆ เขียน comment กันมาได้เลยครับ

ขอบคุณครับ

download source code

เมื่อโหลดไปแล้วใช้คำสั่ง npm install package ต่างๆ ก็จะโหลดให้โดยอัตโนมัติครับ