in search of javascript code quality: unit testing
TRANSCRIPT
IN S
EARCH OF
JAVA
SCRIPT
CODE QUALIT
Y: UNIT
TESTI
NG
WH
Y ? HO
W? W
HAT ?
AGENDA
Unit Testing Concept
Why Unit Testing?
Test Driven Development (a.k.a. TDD)
Basic Terms & Structure
Tools & Libraries
Unit Testing Specifics in JavaScript
Best Practices
UNIT T
ESTING C
ONCEPT
UNIT TESTING CONCEPT
Unit is the smallest testable piece of code.
Unit testing is a method by which individual units of source codeare tested to determine if they are fit for use.
Unit tests are created by programmers.
WHY
UNIT T
ESTING?
COMMON SENSE OR WHY UNIT TESTING?
Unit tests find problems early in the development cycle (TDD & BDD)
RefactoringIntegration
DocumentationBetter design
IS UNIT TESTING A GOOD INVESTMENT?
Might slow down the development process.
The tests may share the same blind spots with the code.
Proving that components X and Y both work independently doesn’t prove that they’re compatible with one another or configured correctly.
TEST
DRIVEN
DEVELOPM
ENT
TD
D
TEST DRIVEN DEVELOPMENT(TDD)
Test-driven development is related to the test-first programming concepts of extreme programming (XP).
TDD is a software development process that relies on the repetition of short development cycle shown on the screen to the left.
Behavior-driven development(BDD) based on TDD…
ALRIGHT, SO WHAT IS BDD YOU ASK?
Behavior-driven development (BDD) isn't anything new or revolutionary. It's just TDD with any test-related terminology replaced by examples-of-behavior-related terminology:
TDD term BDD term
Test Example
Assertion Expectation
assert should, expect
Unit Behavior
Verification Specification
BASIC T
ERMS
AS
SE
RT
I ON
, F I X
TU
RE
, M
OC
K, S
TU
B,
SP Y
ASSERTION
In simple words, the goal of assertion is to forcefully define if the test fails or passes.
Example #1:
Statement Passes(True) Fails(False)
x = 1; assert (x > 0) assert (x < 0)
x++; assert (x > 1) assert (x < 1)
ASSERTION: EXAMPLE
Example(Chai) #2:
Given the function initialize():
function initialize() {
//… Some code goes here …
// The initialization went successfully.
return true;
}
Check that function initialize() returns true when called.
var isInitialized = initialize();
TDD syntax BDD syntax
assert.isTrue(isInitialized) expect(isInitialized).to.be.true
FIXTURE
A test fixture is a fixed state of the software under test used as a baseline for running tests.
In JavaScript: simulate AJAX responses; loading known set of data, such as html objects.
Example(Jasmine):
Require the piece of markup stored in myfixturemarkup.html file before each test:
beforeEach(function() {
loadFixtures('myfixturemarkup.html');
});
STUB
Method stubs are functions with pre-programmed behavior.
Example (Sinon):
Forcing a method to throw an error in order to test error handling.
var fn = foo.stub().throws(Error);
expect(fn).to.throw(Error);
SPY
A test spy is a function that records arguments, return value, the value of this and exception thrown (if any) for all its calls.
Example(Sinon):
Test that a function cursor.hide() has been only called once, and only once.
sinon.spy(cursor, "hide");
TDD
sinon.assert.calledOnce(cursor.hide)
BDD
expect(cursor.hide.calledOnce).to.be.true
MOCK
Mocks are fake objects with pre-programmed behavior (like stubs) and pre-programmed expectations. They are like both stubs and spies – in one.
Mocks isolate the imitate the dependency and thus isolate the unit test.
MOCK: EXAMPLEExample(Sinon):
Create an expectation that jQuery.each is called once, and only once, and also instructs the mock to behave as we pre-define.
var mock = sinon.mock(jQuery);
#1 – which method?(“jQuery.each”)
#2 – how many times it is called?(only once)
#3 – what are the arguments when the method called? (1, {})
#4 – what the method returns? (empty object)
BASIC S
TRUCTU
RE
I N E
NG
L I SH
AN
D I
N J
AV
AS
CR
I PT
BASIC STRUCTURE
#1. Setup/BeforeEach/Before
#2. Prepare an input
#3. Call a method
#4. Check an output
#5. Tear down/AfterEach/After
BASIC STRUCTURE EXPLAINED
#1. Setup/BeforeEach/Before.
before(function(done) {
// Create a basic document.
document = jsdom.jsdom();
window = document.parentWindow;
done();
});
BASIC STRUCTURE EXPLAINED
before(function() { console.log(‘before test’); });
test(‘first test', function() { console.log(‘first test’); });
test(‘second test', function() { console.log(‘second test’); });
afterEach(function() { console.log(‘after each test’); });
Result:
before test
first test
after each test
second test
after each test
BASIC STRUCTURE EXPLAINED
it('should not initialize cursor if zoom level <= minimum zoom level.',
function(done) {
#2. Prepare an input and predicted result.
var zoomLevel = 1;
var expectedCursor = {‘color’: ‘white’, ‘height’: ‘32px’, etc…};
#3. Call a method.
var actualCursor = cursor.init(zoomLevel);
#4. Check an output.
expect(actualCursor).to.deep.equal(expectedCursor);
done();
});
BASIC STRUCTURE EXPLAINED
#5. Tear down/AfterEach/After.
after(function(done) {
// Remove global objects document.
document = null;
window = null;
done();
});
OUTPUT
OUTPUT: SUCCESS
<testsuite name="Macchiato Tests" tests="13" failures="0" errors="0" skipped="0" timestamp="Mon, 02 Dec 2013 11:08:09 GMT" time="0.114">
<testcase classname=“cursor #init ()" name="should not
initialize cursor if zoom level < minimum
zoom level.”
time="0.004"/>
</testsuite>
OUTPUT: FAILURE
<failure classname="cursor #init()" name="should not initialize cursor if zoom level < minimum zoom level." time="0" message="Cannot read property 'show' of undefined"><![CDATA[TypeError: Cannot read property 'show' of undefined
// ..... Exception Stack Trace .....
</failure>
TOOLS
TOOLS
No framework
Known frameworks: qUnit(TDD) Jasmine(BDD) Mocha+ Chai(TDD & BDD)+ Sinon Etc…
TOOLS
What we use:
Run UT: Mocha Run UT in parallel: Macchiato Assert/Expect: Chai W3C DOM in JavaScript: Jsdom Mock, spy, stub: Sinon Code coverage tool: None
UNIT T
ESTING S
PECIFI
CS
IN JA
VASCRIP
T
DO
M,
AJ A
X,
3R
D - P AR
TY
LI B
RA
RI E
S
UNIT TESTING SPECIFICS IN JAVASCRIPTStubbing jQuery plugin functions(mock jQuery.fn)
Testing Ajax requests
Stub jQuery.ajax
Fake XMLHttpRequest(XMLHTTP ActiveXObject)
Fake server
Mocking DOM elements
Load fake data via “fixtures”
Use W3C Javascript implementation Jsdom
BEST PR
ACTICES
BEST PRACTICES
Fast
Isolated
Consistent
Responsibility
Self-descriptive
No exception Handling
Use assertions when needed
THANK YO
U
About m
e & C
onta
cts
http://da-14.com/
akhabibullina
_khabibullina
ua.linkedin.com/pub/anna-khabibullina/38/566/463/
Senior Frontend Developer at GlobalLogicCo-founder of IT company DA-14Contributor of HoganJs, Backbone.Validations