Subscribe via RSS Feed

JavaScript Testing Framework – Jasmine – a quick study

July 22, 2013 1 Comment

Now-a-days various JavaScript based applications are being increasingly popular. So there are requirements to test JavaScript code in automated way are being evident in all aspects of development work.

Below is a short study on

JavaScript Testing Framework – Jasmine

Installation and Running Section -

Install the Jasmine Standalone framework from here.

Unzip the folder.

Put the TestSpce code in <<your functional_spec>>.js file in spec folder within jasmine standalone folder.

Put the JavaScript code in <<your functionality>>.js file in src folder within jasmine standalone folder.

Now

attach the script tag of source JavaScript file in include source files here section in the SpecRunner.html file in jasmine installation folder.

attach the script tag of spec JavaScript file in include spec files here section in the SpecRunner.html file in jasmine installation folder.

Now if we run the SpecRunner.html, sample specs should be passed and the messages should be shown in SpecRunner.html File.

That is it for installation…

Some  points to understand within Jasmine -

1.  Jasmine is a javascript testing framework which is suited for behaviour driven development

2. ‘describe’ is a keyword in test suite for jasmine tests

3. tests in jasmine testing framework is defined by ‘it’ within the ‘describe’ block. 

4. These are individual test units under jasmine framework

5. In ‘describe’ and ‘it’ block, any javascript executable function can run.

6. Any variable declared within ‘describe’ function, will be available in all ‘it’ functions within the particular ‘describe’ function block

7. Expectations are the function which expect actual value to be compared with values returned from function.

8. Matchers do boolean comparison with actual value and expected value. It reports jasmine to have expectation as true or false.

Below are some coding for testing and explained within comments -

Our JavaScript Source file code – (Some minimum coding with Prototype based JavaScript Class) -

If reader is not familiar with JavaScript Classes, he/she can go through Javascript in OOP Way – some interesting study.

// simple javascript functions 
function helloWorld() {
    return "Hello world!";
}

function checkArraylength() {
	var arr = new Array();
	arr[0] = 12;
	//arr[1] = 123;
	return arr.length;
}

// Javascript prototype based class
function AddressWithPrototype(streetno, streetaddress, city, state, country, pincode) {
			this.streetno = streetno;
			this.streetaddress = streetaddress;
			this.city = city;
			this.state = state;
			this.country = country;
			this.pincode =  pincode;
		}

AddressWithPrototype.prototype.fullAddress = function() {
	return 'Full Address is (prototype) -->>' + '\n' + this.streetno + ' ' + this.streetaddress + '\n'                         + this.city + ' ' + this.pincode + '\n' + this.state + ' ' + this.country;
}

AddressWithPrototype.prototype.changeAddressForCity = function() {
    this.city = 'Delhi';
	return 'Full Address is (prototype) -->>' + '\n' + this.streetno + ' ' + this.streetaddress + '\n'                         + this.city + ' ' + this.pincode + '\n' + this.state + ' ' + this.country;
}

Our Test Spec Codes are as follows -

 
describe("Hello world", function() {  // Jasmine Test Suite
    it("says hello", function() {     // Individual Test Component - refer to our source javaScript file code
        expect(helloWorld()).toEqual("Hello world!");  // Equality checking with function output
    }); 
    it("says world1", function() {
        expect(helloWorld()).toContain("world");      // Checking of particular value in function output
    });
    // Adding own Matchers
    beforeEach(function() {
        this.addMatchers({
            toContainElementMoreThanZero: function() {  // Creating custom Matcher
                return (this.actual > 0);
            }
        });
    });
    it('contains more than one array element', function() {
        expect(checkArraylength()).toContainElementMoreThanZero(); // Applying Custom Matcher
    });
    var newAddress;
    beforeEach(function() {
		newAddress = new AddressWithPrototype("4C", "Chidam Mudi Lane", 
                "Kolkata", "West Bengal", "India", "700006");  // Refer to source JavaScript Class
    });
    it("calls the fullAddress() function", function() {
        spyOn(newAddress, "fullAddress");  // invocation of fullAddress method of Class will be checked
        newAddress.fullAddress();
        expect(newAddress.fullAddress).toHaveBeenCalled(); // Calling of method will be ensured
    });
    it("calls with 'Delhi' as argument", function() {
        spyOn(newAddress, "changeAddressForCity");
        newAddress.changeAddressForCity("Delhi");
	expect(newAddress.changeAddressForCity).toHaveBeenCalledWith("Delhi"); // Called with 'Delhi' as argument
    });
    it("not called with 'Kolkata' as argument", function() {
        spyOn(newAddress, "changeAddressForCity");
        newAddress.changeAddressForCity("Delhi");
	expect(newAddress.changeAddressForCity).not.toHaveBeenCalledWith("Kolkata"); 
    })
    it("return delhi as city", function() {
        newAddress.changeAddressForCity();
        expect(newAddress.fullAddress()).toContain("Delhi");
    });
});

// Asynchronous Functionality Testing
describe("async tests", function(){
 var flag, value;
 it("should simulate an asynchronous call", function () { 
  runs(function() { 
    flag  = false; 
    value = 0; 

    setTimeout(function() { // This function will be called after 500 miliseconds
      value++; 
      flag = true; 
    }, 500); 
  });  

  waitsFor(function() {     // Waiting till value return from the function call 
    return flag; 
  }, "The Value should be incremented", 5000);  // If no result found after waiting for 5 seconds, then exit from
                                                // framework method    
  runs(function() {  
    expect(flag).toEqual(true);   
    expect(value).toEqual(1); 
  }); 
 }); 
});
// We will try with actual asynchronous function later and update above scenario

Other key points related to jasmine to be noted are as follows -

Some of the Key features which we can use in jasmine tests

Scenario 1 -
var a;
a = true;
expect(a).toBe(true); <– here .toBe is a keyword for testing
expect(false).not.toBe(true); <– another variation of test with not keyword

Scenario 2 – matcher for regular expressions
var message = ‘It is an address’;
expect(message).toMatch(‘address’); <– here .toMatch is a keyword for testing
expect(message).toMatch(/address/);

Scenario 3 – matcher to compare against ‘undefined’
var person = ‘Piyas De’;
expect(person).toBeDefined(); <– here .toBeDefined is a keyword for testing
expect(aotherperson).not.toBeDefined();
or
expect(aotherperson).toBeUndefined(); <– here .toBeUndefined is a keyword for testing

Scenario 4 – Less Than Checking
var amount = 10;
var anotheramount = 12;
expect(anotheramount).not.toBeLessThan(amount); <– here .toBeLessThan is a keyword for testing

Scenario 5 – Throw Checking
function checkThrow() {
return aVariable;
}
expect(checkThrow()).toThrow(); <– here .toThrow is a keyword for testing
function checkNotThrow() {
return 1;
}
expect(checkNotThrow()).not.toThrow();

For all the details of testing functions in Jasmine -

Reference -

Jasmine Documentation

For now upto this….

If you find this article helpful, you can connect us in Google+ and Twitter for other updates….

Enter your email address:

Delivered by FeedBurner