Sunday, April 10, 2016

JASMINE



Setting up Jasmine
----------------------------
You have many options for running your Jasmine tests. Tests can be run manually, in browsers, headless outside a browser, via a continuous integration server (CI), and so on. The unit tests are written the same way regardless of how they are run. Some examples of how to run them are:
  • SpecRunner.html: Available in the standalone version. You can run tests from a local browser. No server required.
  • From your IDE: For an example of how to run tests automatically from Eclipse, see this post from Misko Heverly.
  • JS-Test-DriverAble to run tests in multiple browsers. You can run JS-Test-Driver from your IDE, command line, and so on.
  • Java with Maven: Runs on every check in, and can then test generated JavaScript.
  • Run headless in Rhino, Envy, or Jasmine-headless-webkit: for testing without a browser. Because the headless test does not attach to a browser instance, it can run faster.
  • Many others: check the Jasmine documentation.



The easiest way to get started with Jasmine is to manually run the tests from SpecRunner.html, which comes in the standalone version of Jasmine. You can download the standalone version of Jasmine from the Pivotal GitHub. Be sure to download 1.2.0 rc2 or newer. The 1.1.0 release did not include all the files to run in the SpecRunner.html file.
Un-zip the file and place it anywhere on your local file system. Open the Jasmine folder and take a look at the directory structure. Notice three directories and an html file:
  • lib
  • src
  • spec
  • SpecRunner.html
The most important directory is lib, which contains the Jasmine test framework code. The src and spec directories contain example tests for your reference. SpecRunner.html is the file used to invoke the unit tests.
None of the directories have to use this naming convention. Your tests do not need to be in the same root directory as the Jasmine source files. However, unless you change the Jasmine JavaScript files, those do need to remain in the same directory. In a real world project, you keep the SpecRunner.html, Jasmine test files, and lib files in a directory that is never deployed to your production server. And in the SpecRunner.html file, you source in the JavaScript files you are testing.

Running the unit tests

Launching the SpecRunner.html file in your local browser runs the tests. Jasmine provides a nice view of the test results. If you are not happy with the look or layout of the result display, there are even libraries to change it, such as jasmine-species.

Figure 1. Jasmine provides a view of the test results and has libraries to customize it.

You can change the format and information displayed in the test runner. The browser name, version, and platform are not displayed with the test information. To change the format of the test info, or add more, edit the jasmine-html.js file under libs. Also, use the available libraries in jasmine-reporters to output the report to XML. Some test runners, such as JS-Test-Driver, which runs Jasmine tests, use their own test result display and save the results to a file.

SpecRunner configuration

Open the SpecRunner.html file to see how the tests are defined.

Figure 2. Note how tests are defined in the SpecRunner.html file.

The file contains four blocks of script tags. The first section includes the Jasmine test runner files. In the next two sections, you reference your JavaScript code to be tested as well as the tests. The fourth runs the tests. Notice that the comments for the included script blocks are backwards. Swap them for clarity. Retain this script organization for your tests and code.
At this point you may be thinking: What should I do if I need to test JavaScript in my HTML files? Well, remember the refactor part in the TDD discussion? The specrunner is not set up to include html files. So, refactor your code to separate the JavaScript in to its own JavaScript file, and then source that file into the test and your html. It’s a best practice anyway. The tests are already helping you write better code! If your JavaScript requires manipulating DOM elements, use libraries such as jasmine-fixtures and jasmine-jquery. These libraries allow you to write unit tests with mock html in them.
Let’s look at the example code and tests that came with the Jasmine standalone download. Open the Player.js and Song.js files located in the src directory to review the functions in them. They each contain the basic Object examples Songand Player. Each has several functions and properties.



















Suites: describe Your Tests

A Suite represents a bunch of tests that are related. Each suite in turn contains a set of Expectations that compare the results of the test - called the actual - with the expected value. 
A test suite begins with a call to the global Jasmine function describe with two parameters: a string and a function.
Syntax : 
describe(<String> , <Function>)
String - is a name or title for a spec suite - (usually what is being tested)
<Function> : The function is a block of code that implements the suite.
Example:
describe("A suite", function() {
 ---— What needs to be test
});

Specs:
Suites functions contains the calls to the expectation methods/functions called Specs. 
Specs are defined by calling the global Jasmine function it, which, like describe takes a string and a function. 

describe("A suite", function() { ——————— Suite
it (<String> , <Function> ) ————— Specs 
});

<String> : The string is the title of the spec 
<Function> : and the function is the spec, or test. 
A spec contains one or more expectations that test the state of the code. An expectation in Jasmine is an assertion that is either true or false. 
A spec with all true expectations is a passing spec. 
A spec with one or more false expectations is a failing spec.

As an <actor> I want to <action> so that <achievment>

Expectations are built with the function expect which takes a value, called the actual. It is chained with a Matcher function, which takes the expected value.


Matchers

Each matcher implements a boolean comparison between the actual value and the expected value. It is responsible for reporting to Jasmine if the expectation is true or false. Jasmine will then pass or fail the spec.
  


it("and has a positive case", function() {
    expect(true).toBe(true);
  });
Any matcher can evaluate to a negative assertion by chaining the call to expect with a not before calling the matcher


Example:
describe("A suite", function() {
  it("contains spec with an expectation", function() {
    expect(true).toBe(true);
  });
});

Simple Example of a Jasmine Test Case containing both Spec and Suites
Let's say you're making a program that has one function, which says hello to the entire world
function helloWorld() {
  return "Hello world!";
}

Now you want to run it by Jasmine to see what she thinks. How do we do that?
  1. First, put this lovely file into the /src directory. Let's call it HelloWorld.js
  2. Now define a suite

describe(“HelloWorld", function() {

});

3.Now define a spec
describe(“HelloWorld", function() {
it(“checkingHello”, function(){
expect(helloWorld()).toEqual(“Hello World”); 
});
});


//--- CODE --------------------------
function calculateNumbers(a,b) {
  return a+b;
}



//--- SPECS -------------------------
describe('JavaScript addition operator', function () {
    it('adds two numbers together', function () {
        expect(calculateNumbers(2,2)).toEqual(3);
    });
});



// your applications custom code 
function addValues( a, b ) { 
    return a + b; 
}; 
// the Jasmine test code
describe("addValues(a, b) function", function() { 
    it("should equal 3", function(){ 
        expect( addValues(1, 2) ).toBe( 3 ); 
    });
    it("should equal 3.75", function(){ 
        expect( addValues(1.75, 2) ).toBe( 3.75 ); 
     }); 
    it("should NOT equal '3' as a String", function(){ 
        expect( addValues(1, 2) ).not.toBe( "3" ); 
    }); 
});


var request = require("request");

var base_url = "http://localhost:8080/";

describe("Hello World Server", function() {
  describe("GET /", function() {
    it("returns status code 200", function() {

      request.get(base_url, function(error, response, body) {


      });

    });
  });
});



Next, notice the beforeEach() and afterEach() definitons. These methods are optional but very useful.

beforeEach(function(){ }); afterEach(function(){ });
As the name implies, the beforeEach function is called once before each spec in the describe in which it is called, and the afterEach function is called once after each spec.
Here is the same set of specs written a little differently. The variable under test is defined at the top-level scope — the describe block — and initialization code is moved into a beforeEach function. The afterEach function resets the variable before continuing.
describe("A spec using beforeEach and afterEach", function() { var foo = 0; beforeEach(function() { foo = 1; }); afterEach(function() { foo = 2; }); 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 beforeAll function is called only once before all the specs in describe are run, and the afterAll function is called after all specs finish. These functions can be used to speed up test suites with expensive setup and teardown.
However, be careful using beforeAll and afterAll! Since they are not reset between specs, it is easy to accidentally leak state between your specs so that they erroneously pass or fail.
describe("A spec using beforeAll and afterAll", function() {
  var foo;

  beforeAll(function() {
    foo = 1;
  });

  afterAll(function() {
    foo = 0;
  });

  it("sets the initial value of foo before specs run", function() {
    expect(foo).toEqual(1);
    foo += 1;
  });

  it("does not reset foo between specs", function() {
    expect(foo).toEqual(2);
  });
});





The this keyword

Another way to share variables between a beforeEachit, and afterEach is through the this keyword. Each spec’s beforeEach/it/afterEach has the this as the same empty object that is set back to empty for the next spec’s beforeEach/it/afterEach.
describe("A spec", function() {
  beforeEach(function() {
    this.foo = 0;
  });

  it("can use the `this` to share state", function() {
    expect(this.foo).toEqual(0);
    this.bar = "test pollution?";
  });

  it("prevents test pollution by having an empty `this` created for the next spec", function() {
    expect(this.foo).toEqual(0);
    expect(this.bar).toBe(undefined);
  });
});

Nesting describe Blocks

Calls to describe can be nested, with specs defined at any level. This allows a suite to be composed as a tree of functions. Before a spec is executed, Jasmine walks down the tree executing each beforeEach function in order. After the spec is executed, Jasmine walks through the afterEach functions similarly.
describe("A spec", 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);
  });

  describe("nested inside a second describe", function() {
    var bar;

    beforeEach(function() {
      bar = 1;
    });

    it("can reference both scopes as needed", function() {
      expect(foo).toEqual(bar);
    });
  });
});

Disabling Suites

Suites can be disabled with the xdescribe function. These suites and any specs inside them are skipped when run and thus their results will not appear in the results.
xdescribe("A spec", function() {
  var foo;

  beforeEach(function() {
    foo = 0;
    foo += 1;
  });

  it("is just a function, so it can contain any code", function() {
    expect(foo).toEqual(1);
  });
});

Pending Specs

Pending specs do not run, but their names will show up in the results as pending.
describe("Pending specs", function() {
Any spec declared with xit is marked as pending.
  xit("can be declared 'xit'", function() {
    expect(true).toBe(false);
  });
Any spec declared without a function body will also be marked pending in results.
  it("can be declared with 'it' but without a function");
And if you call the function pending anywhere in the spec body, no matter the expectations, the spec will be marked pending.

No comments:

Post a Comment