

Extending JavaScript with inline unit tests - sergimansilla
http://sergimansilla.com/blog/extending-js-inline-unit-tests/

======
jdlshore
It's an interesting idea. My first reaction is to wonder how it would work
with the more complicated tests you typically encounter in real-world
JavaScript.

For example, see [1]. This is a very simple example of testing a JavaScript
drawing app. (It's from my Let's Code JavaScript screencast [2].) In this
example, you'll see several things that don't seem like they'd work well with
inline tests:

1\. Common setup and teardown. The tests work against the browser DOM, so
there's `beforeEach()` and `afterEach()` functions that set up and clean up
the DOM. The `afterEach()` function is particularly valuable because it runs
even when exceptions occur. How would common setup and teardown be handled
with inline tests?

2\. Multiple tests per function. There's a fairly loose relationship between
the tests and the functions in the production code. Instead, the tests speak
to the behavior of the drawing app. If these tests were inline, how would you
prevent the test code from overwhelming the production code?

3\. Helper functions. The tests have a lot of helper functions to do things
like simulate events and parse the DOM. This particular example is worse than
most, but helper functions are still fairly common when testing. How do you
distinguish test-specific helper functions from production functions when
you're using inline tests?

Overall, I wonder if inline tests would make this code harder to read, not
easier.

I'm intrigued by the idea, so this isn't meant to be a middlebrow dismissal,
but more an invitation to explore real-world problems. Feel free to use my
example code at a starting point! I'd love to see a clever transformation of
this code to inline testing.

[1] The example code:
[https://github.com/jamesshore/ll11_front_end_unit_testing/bl...](https://github.com/jamesshore/ll11_front_end_unit_testing/blob/master/src/_example_test.js)

[2] Let's Code: Test-Driven JavaScript, my screencast:
[http://www.letscodejavascript.com](http://www.letscodejavascript.com)

------
ghostdiver
This technique is not called "Inline unit tests", it's called contract
programming.

I can't imagine writing such code without proper support from IDE like
automatic folding and/or special colors.

There is also problem of asynchronous code, events etc. Something that can't
be covered with such simple contracts.

~~~
sergimansilla
Given the simplicity of my macro, I didn't call this 'contract programming' on
purpose. For real JavaScript Contract Programming, check out contracts.js
(from the same author of sweet.js).

~~~
ghostdiver
Among others(there are many contract implementations for js on github) this
one is pretty average, not modern enough, not compatible with code which uses
promises. Such implementation should go beyond direct arguments and result
value of function call.

------
willvarfar
Skipping the `where` and just putting the asserts after the function
definition would be as readable, maintainable and skip needing sweet.js
processing cost?

~~~
jpolitz
A few things that Pyret gets out of "where" blocks that it's not obvious are
easy with just assertions after the function.

\- Reporting failures can more easily report context about the function being
tested

\- Since "where" blocks are actual blocks, we define helper functions and
variables inside them that don't need to clutter up the namespace of the
current scope

\- It's easy to turn the assertions on and off; for example when importing a
Pyret module we skip running the checks of that module by default.

\- The localized information also plays into our story for type inference
(which is work in progress), but starts from the unit tests in the where:
block to figure out what the programmer intended for input/output types.

------
cj
Here's a simple implementation without sweet.js:

    
    
      var inlineTest = function(fn, tests) {
        (tests || []).forEach(function(test){
          if (fn.apply(this, test[0]) !== test[1]) {
            throw new Error('Failed inline unit test with args: ' + test[0]);
          }
        });
        return fn;
      };
    
      var square = inlineTest(function(n){
        return n * n;
      }, [
        [[2],4], // [[arrayOfArguments], expectedResult]
        [[3],5]  // <-- This test will throw an error
      ]);
    
    

EDIT: Change fn.call to fn.apply

~~~
tiles
Nice. If you wanted to go even more inline:

    
    
        Function.prototype.where = function () {
            var fn = this, tests = [].slice.apply(arguments);
            (tests || []).forEach(function(test){
              if (fn.call(this, test[0]) !== test[1]) {
                throw new Error('Failed inline unit test with args: ' + test[0]);
              }
            });
            return fn;
        };
        
          var square = function(n){
            return n * n;
          }.where(
            [[2], 4], // [[arrayOfArguments], expectedResult]
            [[3], 5]  // <-- This test will throw an error
          );

~~~
camus2
you just gave me an idea for a "typechecking" api.thanks.

~~~
jordanwallwork
I wrote something like this once, never did anything with it but you might
find it useful: [http://jordanwallwork.co.uk/2013/01/faking-typed-function-
ov...](http://jordanwallwork.co.uk/2013/01/faking-typed-function-overloading-
in-javascript/)

------
_random_
Patching dynamic weak typed system, sigh...

