I've looked into and considered many JavaScript unit tests and testing tools, but have been unable to find a suitable option to remain fully TDD compliant. So, is there a JavaScript unit test tool that is fully TDD compliant?
JavaScript unit test tools for TDD
javascripttddunit testing
Related Solutions
Update:
Some 10 years later perhaps the best way to test a private method, or any inaccessible member, is via
@Jailbreak
from the Manifold framework.@Jailbreak Foo foo = new Foo(); // Direct, *type-safe* access to *all* foo's members foo.privateMethod(x, y, z); foo.privateField = value;
This way your code remains type-safe and readable. No design compromises, no overexposing methods and fields for the sake of tests.
If you have somewhat of a legacy Java application, and you're not allowed to change the visibility of your methods, the best way to test private methods is to use reflection.
Internally we're using helpers to get/set private
and private static
variables as well as invoke private
and private static
methods. The following patterns will let you do pretty much anything related to the private methods and fields. Of course, you can't change private static final
variables through reflection.
Method method = TargetClass.getDeclaredMethod(methodName, argClasses);
method.setAccessible(true);
return method.invoke(targetObject, argObjects);
And for fields:
Field field = TargetClass.getDeclaredField(fieldName);
field.setAccessible(true);
field.set(object, value);
Notes:
1.TargetClass.getDeclaredMethod(methodName, argClasses)
lets you look intoprivate
methods. The same thing applies forgetDeclaredField
.
2. ThesetAccessible(true)
is required to play around with privates.
A closure is a pairing of:
- A function, and
- A reference to that function's outer scope (lexical environment)
A lexical environment is part of every execution context (stack frame) and is a map between identifiers (ie. local variable names) and values.
Every function in JavaScript maintains a reference to its outer lexical environment. This reference is used to configure the execution context created when a function is invoked. This reference enables code inside the function to "see" variables declared outside the function, regardless of when and where the function is called.
If a function was called by a function, which in turn was called by another function, then a chain of references to outer lexical environments is created. This chain is called the scope chain.
In the following code, inner
forms a closure with the lexical environment of the execution context created when foo
is invoked, closing over variable secret
:
function foo() {
const secret = Math.trunc(Math.random()*100)
return function inner() {
console.log(`The secret number is ${secret}.`)
}
}
const f = foo() // `secret` is not directly accessible from outside `foo`
f() // The only way to retrieve `secret`, is to invoke `f`
In other words: in JavaScript, functions carry a reference to a private "box of state", to which only they (and any other functions declared within the same lexical environment) have access. This box of the state is invisible to the caller of the function, delivering an excellent mechanism for data-hiding and encapsulation.
And remember: functions in JavaScript can be passed around like variables (first-class functions), meaning these pairings of functionality and state can be passed around your program: similar to how you might pass an instance of a class around in C++.
If JavaScript did not have closures, then more states would have to be passed between functions explicitly, making parameter lists longer and code noisier.
So, if you want a function to always have access to a private piece of state, you can use a closure.
...and frequently we do want to associate the state with a function. For example, in Java or C++, when you add a private instance variable and a method to a class, you are associating state with functionality.
In C and most other common languages, after a function returns, all the local variables are no longer accessible because the stack-frame is destroyed. In JavaScript, if you declare a function within another function, then the local variables of the outer function can remain accessible after returning from it. In this way, in the code above, secret
remains available to the function object inner
, after it has been returned from foo
.
Uses of Closures
Closures are useful whenever you need a private state associated with a function. This is a very common scenario - and remember: JavaScript did not have a class syntax until 2015, and it still does not have a private field syntax. Closures meet this need.
Private Instance Variables
In the following code, the function toString
closes over the details of the car.
function Car(manufacturer, model, year, color) {
return {
toString() {
return `${manufacturer} ${model} (${year}, ${color})`
}
}
}
const car = new Car('Aston Martin','V8 Vantage','2012','Quantum Silver')
console.log(car.toString())
Functional Programming
In the following code, the function inner
closes over both fn
and args
.
function curry(fn) {
const args = []
return function inner(arg) {
if(args.length === fn.length) return fn(...args)
args.push(arg)
return inner
}
}
function add(a, b) {
return a + b
}
const curriedAdd = curry(add)
console.log(curriedAdd(2)(3)()) // 5
Event-Oriented Programming
In the following code, function onClick
closes over variable BACKGROUND_COLOR
.
const $ = document.querySelector.bind(document)
const BACKGROUND_COLOR = 'rgba(200,200,242,1)'
function onClick() {
$('body').style.background = BACKGROUND_COLOR
}
$('button').addEventListener('click', onClick)
<button>Set background color</button>
Modularization
In the following example, all the implementation details are hidden inside an immediately executed function expression. The functions tick
and toString
close over the private state and functions they need to complete their work. Closures have enabled us to modularise and encapsulate our code.
let namespace = {};
(function foo(n) {
let numbers = []
function format(n) {
return Math.trunc(n)
}
function tick() {
numbers.push(Math.random() * 100)
}
function toString() {
return numbers.map(format)
}
n.counter = {
tick,
toString
}
}(namespace))
const counter = namespace.counter
counter.tick()
counter.tick()
console.log(counter.toString())
Examples
Example 1
This example shows that the local variables are not copied in the closure: the closure maintains a reference to the original variables themselves. It is as though the stack-frame stays alive in memory even after the outer function exits.
function foo() {
let x = 42
let inner = function() { console.log(x) }
x = x+1
return inner
}
var f = foo()
f() // logs 43
Example 2
In the following code, three methods log
, increment
, and update
all close over the same lexical environment.
And every time createObject
is called, a new execution context (stack frame) is created and a completely new variable x
, and a new set of functions (log
etc.) are created, that close over this new variable.
function createObject() {
let x = 42;
return {
log() { console.log(x) },
increment() { x++ },
update(value) { x = value }
}
}
const o = createObject()
o.increment()
o.log() // 43
o.update(5)
o.log() // 5
const p = createObject()
p.log() // 42
Example 3
If you are using variables declared using var
, be careful you understand which variable you are closing over. Variables declared using var
are hoisted. This is much less of a problem in modern JavaScript due to the introduction of let
and const
.
In the following code, each time around the loop, a new function inner
is created, which closes over i
. But because var i
is hoisted outside the loop, all of these inner functions close over the same variable, meaning that the final value of i
(3) is printed, three times.
function foo() {
var result = []
for (var i = 0; i < 3; i++) {
result.push(function inner() { console.log(i) } )
}
return result
}
const result = foo()
// The following will print `3`, three times...
for (var i = 0; i < 3; i++) {
result[i]()
}
Final points:
- Whenever a function is declared in JavaScript closure is created.
- Returning a
function
from inside another function is the classic example of closure, because the state inside the outer function is implicitly available to the returned inner function, even after the outer function has completed execution. - Whenever you use
eval()
inside a function, a closure is used. The text youeval
can reference local variables of the function, and in the non-strict mode, you can even create new local variables by usingeval('var foo = …')
. - When you use
new Function(…)
(the Function constructor) inside a function, it does not close over its lexical environment: it closes over the global context instead. The new function cannot reference the local variables of the outer function. - A closure in JavaScript is like keeping a reference (NOT a copy) to the scope at the point of function declaration, which in turn keeps a reference to its outer scope, and so on, all the way to the global object at the top of the scope chain.
- A closure is created when a function is declared; this closure is used to configure the execution context when the function is invoked.
- A new set of local variables is created every time a function is called.
Links
- Douglas Crockford's simulated private attributes and private methods for an object, using closures.
- A great explanation of how closures can cause memory leaks in IE if you are not careful.
- MDN documentation on JavaScript Closures.
Related Topic
- Javascript – Remove properties from objects (JavaScript)
- Javascript – Which equals operator (== vs ===) should be used in JavaScript comparisons
- Javascript – How to test for an empty JavaScript object
- Javascript – How to include a JavaScript file in another JavaScript file
- Javascript – What does “use strict” do in JavaScript, and what is the reasoning behind it
- Javascript – How to check whether a string contains a substring in JavaScript
- Javascript – How to decide when to use Node.js
- Javascript – For-each over an array in JavaScript
Best Answer
Karma or Protractor
Karma is a JavaScript test-runner built with Node.js and meant for unit testing.
The Protractor is for end-to-end testing and uses Selenium Web Driver to drive tests.
Both have been made by the Angular team. You can use any assertion-library you want with either.
Screencast: Karma Getting started
related:
pros:
Cons:
mocha.js
I'm totally unqualified to comment on mocha.js's features, strengths, and weaknesses, but it was just recommended to me by someone I trust in the JS community.
List of features, as reported by its website:
yolpo
Yolpo is a tool to visualize the execution of javascript. Javascript API developers are encouraged to write their use cases to show and tell their API. Such use cases forms the basis of regression tests.
AVA
Futuristic test runner with built-in support for ES2015. Even though JavaScript is single-threaded, IO in Node.js can happen in parallel due to its async nature. AVA takes advantage of this and runs your tests concurrently, which is especially beneficial for IO heavy tests. In addition, test files are run in parallel as separate processes, giving you even better performance and an isolated environment for each test file.
Buster.js
A JavaScript test-runner built with Node.js. Very modular and flexible. It comes with its own assertion library, but you can add your own if you like. The assertions library is decoupled, so you can also use it with other test-runners. Instead of using
assert(!...)
orexpect(...).not...
, it usesrefute(...)
which is a nice twist imho.Screencast: Buster.js Getting started (2:45)
pros:
Cons:
* TestSwarm is also a Continuous Integration server, while you need a separate CI server for Buster.js. It does, however, output xUnit XML reports, so it should be easy to integrate with Hudson, Bamboo or other CI servers.
TestSwarm
https://github.com/jquery/testswarm
TestSwarm is officially no longer under active development as stated on their GitHub webpage. They recommend Karma, browserstack-runner, or Intern.
Jasmine
This is a behavior-driven framework (as stated in quote below) that might interest developers familiar with Ruby or Ruby on Rails. The syntax is based on RSpec that are used for testing in Rails projects.
Jasmine specs can be run from an html page (in qUnit fashion) or from a test runner (as Karma).
If you have experience with this testing framework, please contribute with more info :)
Project home: http://jasmine.github.io/
QUnit
QUnit focuses on testing JavaScript in the browser while providing as much convenience to the developer as possible. Blurb from the site:
QUnit shares some history with TestSwarm (above):
Project home: http://qunitjs.com/
Sinon
Another great tool is sinon.js by Christian Johansen, the author of Test-Driven JavaScript Development. Best described by himself:
Intern
The Intern Web site provides a direct feature comparison to the other testing frameworks on this list. It offers more features out of the box than any other JavaScript-based testing system.
JEST
A new but yet very powerful testing framework. It allows snapshot based testing as well this increases the testing speed and creates a new dynamic in terms of testing
Check out one of their talks: https://www.youtube.com/watch?v=cAKYQpTC7MA
Better yet: Getting Started