Mocha has several \'hooks\' to run assistive functionality in a test separate from the test cases themselves (clearing databases, creating mock files, etc).
However,
Put directly inside a describe
callback code that will build the test suite. I'm talking about calls to it
but also functions that may loop over tables or files to declare a bunch of tests (by calling it
in the loop).
Put inside hooks the code that actually initialize the state that the tests depend on.
All other considerations are quite secondary.
Let me explain...
Mocha executes a test suite in two phases:
It discovers what tests exist. During this phase it will immediately execute the callbacks passed to describe
and record for future invocation the callbacks passed to the functions that declare tests (it
and the like) and functions that declare hooks (before
, beforeEach
, after
, etc.).
It runs the tests. In this phase it will run the callbacks that it recorded earlier.
So consider this example:
function dump () { console.log("running:", this.test.fullTitle()); }
describe("top", function () {
before(dump);
it("test 1", dump);
it("test 2", dump);
describe("level 1", function () {
before(dump);
it("test 1", dump);
it("test 2", dump);
});
});
Note that fullTitle
gives the whole name of a test starting from the top level describe
, going through any nested describe
down to the it
or hook that contains the call. Run with the spec
reporter and keeping only the running:
lines, you get:
running: top "before all" hook: dump
running: top test 1
running: top test 2
running: top level 1 "before all" hook: dump
running: top level 1 test 1
running: top level 1 test 2
Note the order of the hooks, and how each executes immediately before the tests declared in its respective describe
callback.
Consider then this suite:
function dump () { console.log("running:", this.test.fullTitle()); }
function directDump() { console.log("running (direct):", this.fullTitle()); }
describe("top", function () {
directDump.call(this);
it("test 1", dump);
it("test 2", dump);
describe("level 1", function () {
directDump.call(this);
it("test 1", dump);
it("test 2", dump);
});
});
Run with the spec
reporter and keeping only the running:
lines, you get:
running (direct): top
running (direct): top level 1
running: top test 1
running: top test 2
running: top level 1 test 1
running: top level 1 test 2
Note how both calls to directDump
are run before anything else.
If any initialization code that you put directly inside a callback to describe
fails, the entire run fails right away. No test will be executed. End of story.
If any initialization code that you put inside a before
hook fails, the consequences are contained. For one thing, because a before
hook is run just at the moment is needed, there is an opportunity any tests that are scheduled earlier can run. Also, Mocha will only skip those tests that depend on the before
hook. For instance, let's assume this suite:
function dump () { console.log("running:", this.test.fullTitle()); }
describe("top", function () {
before(dump);
it("test 1", dump);
it("test 2", dump);
describe("level 1", function () {
before(function () { throw new Error("foo"); });
it("test 1", dump);
it("test 2", dump);
});
describe("level 1 (second)", function () {
before(dump);
it("test 1", dump);
it("test 2", dump);
});
});
If you run it with the spec
reporter, the entire output (minus the stack trace) will be something like:
top
running: top "before all" hook: dump
running: top test 1
✓ test 1
running: top test 2
✓ test 2
level 1
1) "before all" hook
level 1 (second)
running: top level 1 (second) "before all" hook: dump
running: top level 1 (second) test 1
✓ test 1
running: top level 1 (second) test 2
✓ test 2
4 passing (5ms)
1 failing
1) top level 1 "before all" hook:
Error: foo
[stack trace]
Note how a) some tests ran before the failing hook and b) Mocha still ran the tests that do not depend on the hooks.