47
1 Test Driven development & Jasmine Anup Singh https://in.linkedin.com/in/anupsinghpune

JAVASCRIPT Test Driven Development & Jasmine

Embed Size (px)

Citation preview

Page 1: JAVASCRIPT Test Driven Development & Jasmine

1

Test Driven development & Jasmine

Anup Singh

https://in.linkedin.com/in/anupsinghpune

Page 2: JAVASCRIPT Test Driven Development & Jasmine

Points to Discuss

• Unit Testing & Test Driven Development

• Debugging JS

• Writing Testable Code

• Designing own testing framework

• Jasmine

• Testing Forms

2https://in.linkedin.com/in/anupsinghpune

Page 3: JAVASCRIPT Test Driven Development & Jasmine

How do you test your JS?

1. Write your JavaScript code

2. See if it works in your favourite browser

3. Change something + [F5]

4. If it doesn't work repeat #3 until you make it work or you go crazy...

5. In case you made it work, discover few days/weeks later that it doesn't work in another browser

3https://in.linkedin.com/in/anupsinghpune

Page 4: JAVASCRIPT Test Driven Development & Jasmine

I think I'm going crazy...

4https://in.linkedin.com/in/anupsinghpune

Page 5: JAVASCRIPT Test Driven Development & Jasmine

Unit Testing

• In computer programming, unit testing is a procedure used to validate that individual modules or units of source code are working properly.

• Unit testing is used for

(i) Test Driven Development

(ii) Fixing bugs

(iii) Regression testing

5https://in.linkedin.com/in/anupsinghpune

Page 6: JAVASCRIPT Test Driven Development & Jasmine

Test Driven Development

• Test-Driven Development (TDD) is a computer programming technique that involves repeatedly first writing a test case and then implementing only the code necessary to pass the test.

• Test-driven development is a method of designing software, not merely a method of testing.

6https://in.linkedin.com/in/anupsinghpune

Page 7: JAVASCRIPT Test Driven Development & Jasmine

Test Driven Development

• TDD in its simplest form is just this:

– Write your tests

– Watch them fail

– Make them pass

– Refactor

– Repeat

7https://in.linkedin.com/in/anupsinghpune

Page 8: JAVASCRIPT Test Driven Development & Jasmine

The TDD Micro-Cycle

8https://in.linkedin.com/in/anupsinghpune

Page 9: JAVASCRIPT Test Driven Development & Jasmine

Fixing bugs/Regression Testing

9

• Fixing bugs

• Regression testing

https://in.linkedin.com/in/anupsinghpune

Page 10: JAVASCRIPT Test Driven Development & Jasmine

What do you need?

• A Unit Testing framework• Development Environment

10https://in.linkedin.com/in/anupsinghpune

Page 11: JAVASCRIPT Test Driven Development & Jasmine

Tools Firebug - The popular developer extension for Firefox that got the ball rolling.

See http://getfirebug.org/. IE Developer Tools - Included in Internet Explorer 8 and later. Opera Dragonfly - Included in Opera 9.5 and newer. Also works with mobile versions of Opera. WebKit Developer Tools - Introduced in Safari 3, dramatically improved as of Safari 4, and now available in Chrome.

Logging - http://patik.com/blog/complete-cross-browser-console-log/

1. alert()2. Console.log()3. Common logging method that for all modern browsers

function log() {try {

console.log.apply(console, arguments);} catch (e) {

try {opera.postError.apply(opera, arguments);

} catch (e) {alert(Array.prototype.join.call(arguments, " "));

}}

}

1. Tries to log message using the most common method

2. Catches any failure in logging

3. Tries to log the Opera way

Uses alert if all else fails

Testing and debugging - Debugging code

Page 12: JAVASCRIPT Test Driven Development & Jasmine

Breakpoints allow us to halt execution at a specific line of code so we can take a gander at the state.<!DOCTYPE html><html><head>

<title>Listing 2.2</title><script type="text/javascript" src="log.js"></script><script type="text/javascript">

var x = 213;log(x);

</script></head><body></body></html>

Testing and debugging - Breakpoints

https://in.linkedin.com/in/anupsinghpune

Page 13: JAVASCRIPT Test Driven Development & Jasmine

Good tests make Good code - Emphasis on the word good. It's quite possible to have an extensive test suite that doesn't really help the quality of our code, if the tests are poorly constructed.

Good tests exhibit three important characteristics:

1. Repeatability - Our test results should be highly reproducible. Tests run repeatedly should always produce

the exact same results. If test results are nondeterministic, how would we know which results are valid and which are invalid?

2. Simplicity - Our tests should focus on testing one thing. We should strive to remove as much HTML markup,

CSS, or JavaScript as we can without disrupting the intent of the test case. The more we remove, the greater the likelihood that the test case will only be influenced by the specific code that we’re testing.

3. Independence - Our tests should execute in isolation. We must avoid making the results from one test

dependent upon another. Breaking tests down into the smallest possible

Test generation

https://in.linkedin.com/in/anupsinghpune

Page 14: JAVASCRIPT Test Driven Development & Jasmine

A test suite should serve as a fundamental part of your development workflow, so you

should pick a suite that works particularly well for your coding style and your codebase.

JavaScript unit testing framework features• The ability to simulate browser behaviour (clicks, keypresses, and so on)• Interactive control of tests (pausing and resuming tests)• Handling asynchronous test timeouts• The ability to filter which tests are to be executed

Testing Frameworks

https://in.linkedin.com/in/anupsinghpune

Page 15: JAVASCRIPT Test Driven Development & Jasmine

Market Share of Testing frameworks

15https://in.linkedin.com/in/anupsinghpune

Page 16: JAVASCRIPT Test Driven Development & Jasmine

The fundamentals of a test suite

The fundamentals of a test suite1. Aggregate all the individual tests into a single unit2. Run the in Bulk3. Providing a single resource that can be run easily and repeatedly

How to construct a test suiteQ. Why would I want to build a new test suite, When There are already a number of good-quality suites to choose from?

A. Building your own test suite can serve as a good learning experience, especially when looking at how

asynchronous testing works.

16https://in.linkedin.com/in/anupsinghpune

Page 17: JAVASCRIPT Test Driven Development & Jasmine

The Assertion – (assert.html)

17

1. The core of a unit-testing framework is its assertion method, usually named assert().

2. This takes a value—an expression whose premise is asserted—and a description that describes the purpose of the assertion. If the value evaluates to true

3. Either the assertion passes or it’s considered a failure.

4. The associated message is usually logged with an appropriate pass/fail indicator.

https://in.linkedin.com/in/anupsinghpune

Page 18: JAVASCRIPT Test Driven Development & Jasmine

Simple Implementation of JavaScript Assertion

18https://in.linkedin.com/in/anupsinghpune

Page 19: JAVASCRIPT Test Driven Development & Jasmine

More Examples -

• Custom/1_jq_test.html

• Custom/assert.html

• Custom/test_group.html

19https://in.linkedin.com/in/anupsinghpune

Page 20: JAVASCRIPT Test Driven Development & Jasmine

Test Groups – (test_group.html)

1. Grouping assertions together in a testing context to form test groups.

2. Test group will likely represent a collection of assertions as they relate to a single method in our API or application

3. If any assertion fails, then the entire test group is marked as failing

20https://in.linkedin.com/in/anupsinghpune

Page 21: JAVASCRIPT Test Driven Development & Jasmine

So what's the first step to sanity?

WRITE TESTABLE CODE

21https://in.linkedin.com/in/anupsinghpune

Page 22: JAVASCRIPT Test Driven Development & Jasmine

What's wrong with this code?

js_sample_001.js

(inline functions and more inside, ajax directly hooked to element, etc.)

22https://in.linkedin.com/in/anupsinghpune

Page 23: JAVASCRIPT Test Driven Development & Jasmine

Anonymous functions, within functions, within functions...

23https://in.linkedin.com/in/anupsinghpune

Page 24: JAVASCRIPT Test Driven Development & Jasmine

I'll put functions in your functions...

24https://in.linkedin.com/in/anupsinghpune

Page 25: JAVASCRIPT Test Driven Development & Jasmine

All your DOM elements are belong to JS!

25https://in.linkedin.com/in/anupsinghpune

Page 26: JAVASCRIPT Test Driven Development & Jasmine

Server URL coupling

js_sample_001.js

(with highlighted hardcoded url)

26https://in.linkedin.com/in/anupsinghpune

Page 27: JAVASCRIPT Test Driven Development & Jasmine

Refactoring...

js_sample_002.js

27https://in.linkedin.com/in/anupsinghpune

Page 28: JAVASCRIPT Test Driven Development & Jasmine

Refactoring...

js_sample_002.js

28https://in.linkedin.com/in/anupsinghpune

Page 29: JAVASCRIPT Test Driven Development & Jasmine

Now that's better...

29

js_sample_003.js

(init func and hooked named functions to

page)

https://in.linkedin.com/in/anupsinghpune

Page 30: JAVASCRIPT Test Driven Development & Jasmine

Now that's better...

30https://in.linkedin.com/in/anupsinghpune

Page 31: JAVASCRIPT Test Driven Development & Jasmine

Now that's better...

31https://in.linkedin.com/in/anupsinghpune

Page 32: JAVASCRIPT Test Driven Development & Jasmine

Now what about testing?

Popular JS Unit-testing frameworks:

QUnit

Jasmine

UnitJS

JsUnit (no longer actively maintained)

Some other – see:http://en.wikipedia.org/wiki/List_of_unit_testing_frameworks#JavaScript

32https://in.linkedin.com/in/anupsinghpune

Page 33: JAVASCRIPT Test Driven Development & Jasmine

Introducing Jasmine

• Testing framework• Suites possess a hierarchical structure• Tests as specifications• Matchers, both built-in and custom• Spies, a test double pattern

33https://in.linkedin.com/in/anupsinghpune

Page 34: JAVASCRIPT Test Driven Development & Jasmine

Jasmine suite

describe("A specification suite", function() {

});

• Group specifications together using nested

describe function blocks.

• Also useful for delineating context-specific

specifications.

34https://in.linkedin.com/in/anupsinghpune

Page 35: JAVASCRIPT Test Driven Development & Jasmine

Jasmine specification

describe("A specification suite", function() {

it(“contains spec with an expectation", function() {

expect(view.tagName).toBe(‘tr’);

});

});

• Specifications are expressed with the it function.

• The description should read well in the report.

• Expectations are expressed with the expect function

35https://in.linkedin.com/in/anupsinghpune

Page 36: JAVASCRIPT Test Driven Development & Jasmine

• The describe function, describes a feature of an application. It acts as an aggregating container for individual tests. You can think of the describe blocks as of test suites. The describe blocks can be nested inside each other.

• The test itself is located inside the it function. The idea is to exercise one particular aspect of a feature in one test. A test has a name and a body. Usually the first section of the test's body calls methods on an object under test while the later one verifies expected results.

• Code contained in the beforeEach block will get executed before each individual test. This is a perfect place for any initialization logic that has to be executed before each test.

• The last things to mention are the expect and the toEqual functions. Using those two constructs we can compare actual results with the expected ones. Jasmine,

comes with a rich set of matchers, toBeTruthy, toBeDefined, toContain are just few examples of what is available.

Jasmine specification

36https://in.linkedin.com/in/anupsinghpune

Page 37: JAVASCRIPT Test Driven Development & Jasmine

Jasmine matchers

• not• toBe• toEqual• toMatch• toBeDefined• toBeUndefined• toBeNull

• toBeTruthy• toBeFalsy• toContain• toBeLessThan• toBeGreaterThan• toBeCloseTo• toThrow

37https://in.linkedin.com/in/anupsinghpune

Page 38: JAVASCRIPT Test Driven Development & Jasmine

Jasmine setup using beforeEach

describe("PintailConsulting.ToDoListView", function() {

var view;

beforeEach(function(){

view = new PintailConsulting.ToDoListView();

});

it(“sets the tagName to ‘div’", function() {

expect(view.tagName).toBe(‘div’);

});});

38https://in.linkedin.com/in/anupsinghpune

Page 39: JAVASCRIPT Test Driven Development & Jasmine

Jasmine tear down using afterEach

describe("PintailConsulting.ToDoListView", function() {

var view;

beforeEach(function(){

view = new PintailConsulting.ToDoListView();

});

afterEach(function(){

view = null;

});

it(“sets the tagName to ‘div’", function() {

expect(view.tagName).toBe(‘div’);

});});

39https://in.linkedin.com/in/anupsinghpune

Page 40: JAVASCRIPT Test Driven Development & Jasmine

Jasmine custom matchers

beforeEach(function() {

this.addMatchers({

toBeLessThan: function(expected) {

var actual = this.actual;

var notText = this.isNot ? " not" : "";

this.message = function () {

return "Expected " + actual + notText + " to be less than " +

expected;

}

return actual < expected;

}

});});

40https://in.linkedin.com/in/anupsinghpune

Page 41: JAVASCRIPT Test Driven Development & Jasmine

Jasmine spies

• Test double pattern.• Interception-based test double mechanism provided by the

Jasmine library.• Spies record invocations and invocation parameters, allowing you

to inspect the spy after exercising the SUT.• Very similar to mock objects.• More information at

https://github.com/pivotal/jasmine/wiki/Spies.

41https://in.linkedin.com/in/anupsinghpune

Page 42: JAVASCRIPT Test Driven Development & Jasmine

Jasmine spy usage

Spying and verifying invocationvar spy = spyOn(dependency, “render”);

systemUnderTest.display();

expect(spy).toHaveBeenCalled();

Spying, verifying invocation and argument(s)

var spy = spyOn(dependency, “render”);

systemUnderTest.display(“Hello”);expect(spy).toHaveBeenCalledWith(“Hello”);

42https://in.linkedin.com/in/anupsinghpune

Page 43: JAVASCRIPT Test Driven Development & Jasmine

Jasmine spy usage

Spying, verifying number of invocations and

arguments for each call

var spy = spyOn(Leaflet, “circle”).andCallThrough();

mapView.processResults(earthquakeJsonResults);

expect(spy).toHaveBeenCalled()

expect(circleConstructorSpy.callCount).toBe(2);

expect(circleConstructorSpy.argsForCall[0][0]).toEqual([56.6812, -155.0237])

43https://in.linkedin.com/in/anupsinghpune

Page 44: JAVASCRIPT Test Driven Development & Jasmine

Loose matching with jasmine.any

• Accepts a constructor or “class” name as an expected

value.

• Returns true if the constructor matches the constructor of

the actual value.

var spy = jasmine.createSpy(My.Namespace, ’foo’);

foo(12, function(x) { return x * x; });

expect(spy).toHaveBeenCalledWith(jasmine.any(Number), jasmine.any(Function));

44https://in.linkedin.com/in/anupsinghpune

Page 45: JAVASCRIPT Test Driven Development & Jasmine

Jasmine spy usage

• andCallThrough(): Allows the invocation to

passthrough to the real subject.

• andReturn(result): Return a hard-coded result.

• andCallFake(fakeImplFunction): Return a

dynamically generated result from a function.

• createSpy(identity): Manually create a spy.

• createSpyObj(identity, propertiesArray): Creates a mock with multiple property spies.

45https://in.linkedin.com/in/anupsinghpune

Page 46: JAVASCRIPT Test Driven Development & Jasmine

Jasmine asynchronous support

• Use runs and waitsFor blocks and a latch function.

• The latch function polls until it returns true or the

timeout expires, whichever comes first.

• If the timeout expires, the specification fails with a

message.• Kind of clunky to use.

46https://in.linkedin.com/in/anupsinghpune

Page 47: JAVASCRIPT Test Driven Development & Jasmine

Jasmine asynchronous example

describe("an async spec", function() {

var done;

beforeEach(function() {

done = false;

var doStuff = function() {

// simulate async stuff and wait 10ms

setTimeout(function() { done = true; }, 10);

};

runs(doStuff);

waitsFor(function() { return done; }, ‘The doStuff function should be done by

now.’, 100);

});

it("did stuff", function() {

expect(done).toBe(true);

});

});

47https://in.linkedin.com/in/anupsinghpune