6

Extensively reading about various assertion frameworks in JavaScript. Is there any kind of de-facto/most common "standard" library/framework? When selecting one - which points are most worth noticing?

The (only) requirement I can think about is close-to-zero performance overhead when in production mode.

4
  • Maybe just a phrasing glitch - but zero performance is production would be bad. Perhaps you mean close-to-zero overhead. Commented Sep 12, 2011 at 15:16
  • 5
    Assertions? Hm, console.assert()? Commented Sep 12, 2011 at 15:18
  • @Marc B: you are right :) fixing it. Commented Sep 12, 2011 at 15:23
  • @Šime Vidas: not sure the function is portable across all the browsers. Commented Sep 12, 2011 at 15:24

4 Answers 4

7

Two possible solutions:

Have your build release script remove the Assert lines.

or

Have your build script override the Assert function so it is just an empty function. Downside to this is if you assert call has logic in it [aka assert( x > 100 , "foo" )] than that logic [x > 100] is still going to be run.

Sign up to request clarification or add additional context in comments.

4 Comments

agreed! so, no way to make the arguments calculation void, right?
Only way is to remove it, or change the assertion language to be more like jUnit/JSUnit/QUnit where you have different checks assertTrue, assertFalse, assertEquals, assertNotSame.
About to approve the answer. Just IF possible - could you please clarify on the latter? Like, if I have assertTrue(a!=b) - what trick can I apply, so that a!=b won't be calculated in production mode (less overhead)?
The jUnit way would be assertNotSame("Checking foo", a, b); And the comparison is done in the function, not in the function call.
5

Here is what I use:

When I'm working on the code I have initDevMode(); at the top of the file I'm working with, and when I'm ready to release to production, I just remove that line and all the asserts just go to an empty function.

/**
 * Log a message to console:
 *  either use jquery's console.error
 *  or a thrown exception.
 *  
 *  call initDevMode(); before use to activate
 *  use with:
 *      assert(<condition>, "message");
 *      eg: assert(1 != 1, "uh oh!");
 *  
 *  Log errors with:
 *       errorLog(message);
 *       eg: errorLog(xhr.status);
 */
assert = function(test, msg) { }
errorLog =function(msg) { }

initDevMode = function() {
    assert = function(test, msg) {
        msg = msg || "(no error message)";
        if(!test) {
            try {
                    throw Error();
                } catch(e) {
                    var foo = e;
                    var lines = e.stack.split('\n');
                    for(i in lines) {
                        if(i > 2) {
                        errorLog(msg + lines[i]);
                    }
                }
            }
        }
        throw("Assertion failed with: " + msg);
    };
    errorLog = function(msg) {
        if(typeof console.error == 'function') { 
            console.error(msg);
        } else {
            function errorLog(msg) {
                console.log("foo");
                setTimeout(function() {
                    throw new Error(msg);
                }, 0);
            }
        }
    };
}

1 Comment

Shouldn't 'throw("Assertion failed")' reside inside 'if (!test)' block?
3

I use the following to replace console.assert when it's unavailable for whatever reason.

It's definitely not a de-facto standard, and it is far from ideal, but it does satisfy your requirement that the assertion not be evaluated in production mode. Also, it shows you the expression that triggered the failed assertion, which aids debugging.

The screwy calling syntax (with a function expression) is there to create a closure, so that the assert function has access to the same variables that its caller had access to.

I suspect that this has high compile-time and run-time overhead, but I haven't attempted to verify that.

function assert(func) {
    var name;
    if (typeof(ENABLE_ASSERTIONS) !== "undefined" && !ENABLE_ASSERTIONS) {
        return;
    }
    name = arguments.callee.caller;
    name = name ? name.name : "(toplevel)";
    if (!func()) {
        throw name + ": assertion failed: " + ('' + func).replace(/function[^(]*\([^)]*\)[^{]*{[^r]*return/, '').replace(/;[ \t\n]*}[ \t\n]*$/, '');
    }
}

Using it looks like:

function testAssertSuccess() {
    var i = 1;
    assert(function() { return i === 1; });
}
function testAssertFailure() {
    var j = 1;
    assert(function() { return j === 2; });
}
ENABLE_ASSERTIONS = true;
testAssertSuccess();
testAssertFailure();

HTH!

Comments

1

Take a look to Jascree; basically it is a tool that can remove assertions with almost arbitrary logic from your code. It is handy to use as a batch processor to generate your production code or for a fastcgi-backed scripts directory that you can use when you need to test performance/profile your code.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.