Port of schuchert.wikispaces.com


javascript.UnitTestingWithJsTestDriver

javascript.UnitTestingWithJsTestDriver

Overview

I’m learning JavaScript (again, and for real this time, I hope). After reading JavaScript: The Good Parts and several online pages, I set out to try some basic TDD in JavaScript. For these instructions (and the soon to be created instructional video), I’m using the following tool set:

This is my first stab at this and I hope to both get a better workflow and better at JavaScript.

Getting Setup

Setup JsTestDriver. Instructions summarized here for convenience.

% mkdir -p RpnCalcDemo/src
% mkdir -p RpnCalcDemo/src-test
% cd RpnCalcDemo 
server: http://localhost:9876

load:
  - src/*.js
  - src-test/*.js
% java -jar JsTestDriver-1.3.3d.jar --port 9876
                 JsTestDriver
Last:1326495229968 | Next:1997 | Server:Waiting...

First Test: Initial X Value is 0

rpn_calculator_test = TestCase("rpn_calculator");

rpn_calculator_test.prototype.testShouldInitiallyBe0 = function() {
	var calc = rpn_calculator();
	assertEquals(0, calc.x());
};
% java -jar JsTestDriver-1.3.3d.jar --tests all
java.lang.IllegalArgumentException: The patterns/paths /Users/Thoughtworks/src
/workspaces/ RpnCalcDemo/src (/Users/Thoughtworks/src/workspaces/RpnCalcDemo/
src)  used in the configuration file didn't match any file, the files patterns/
paths need to be relative /Users/Thoughtworks/src/workspaces/RpnCalcDemo
	at com.google.jstestdriver.PathResolver.expandGlob(PathResolver.java:170)
	at com.google.jstestdriver.PathResolver.resolve(PathResolver.java:109)
	at com.google.jstestdriver.config.ParsedConfiguration.resolvePaths(
ParsedConfiguration.java:98)
	at com.google.jstestdriver.config.Initializer.initialize(Initializer.java:84)
	at com.google.jstestdriver.JsTestDriver.runConfigurationWithFlags(
JsTestDriver.java:259)
	at com.google.jstestdriver.JsTestDriver.runConfiguration(
JsTestDriver.java:211)
	at com.google.jstestdriver.JsTestDriver.main(JsTestDriver.java:144)
Unexpected Runner Condition: The patterns/paths /Users/Thoughtworks/src/
workspaces/RpnCalcDemo/src (/Users/Thoughtworks/src/workspaces/RpnCalcDemo/src)
 used in the configuration file didn't match any file, the files patterns/
paths need to be relative /Users/Thoughtworks/src/workspaces/RpnCalcDemo
 Use --runnerMode DEBUG for more information.
var rpn_calculator = function() {
	var that = {};
	that.x = function() {
		return 0;
	};
	return that;
};
% mkdir logs
% java -jar JsTestDriver-1.3.3d.jar --tests all --testOutput logs
.
Total 1 tests (Passed: 1; Fails: 0; Errors: 0) (1.00 ms)
  Chrome 16.0.912.75 Mac OS: Run 1 tests (Passed: 1; Fails: 0; Errors 0) (1.00 ms)
% ls logs
TEST-Chrome_16091275_Mac_OS.rpn_calculator.xml
<?xml version="1.0" encoding="UTF-8"?>
<testsuite name="Chrome_16091275_Mac_OS.rpn_calculator" errors="0" failures="0" tests="1" time="0.0010">
<testcase classname="Chrome_16091275_Mac_OS.rpn_calculator" name="testShouldInitiallyBe0" time="0.0010"/>
</testsuite>

Next Test: Last Value Entered is X

append to src-test/rpn_calculator_test.js

rpn_calculator_test.prototype.testXShouldBeLastValueEntered = function() {
  var calc = rpn_calculator();
  calc.enter(42);
  assertEquals(42, calc.x());
};
% java -jar JsTestDriver-1.3.3d.jar --tests all --testOutput logs
.E
Total 2 tests (Passed: 1; Fails: 0; Errors: 1) (0.00 ms)
  Chrome 16.0.912.75 Mac OS: Run 2 tests (Passed: 1; Fails: 0; Errors 1) (0.00 ms)
    rpn_calculator.testXShouldBeLastValueEntered error (0.00 ms): TypeError: 
Object #<Object> has no method 'enter'
      TypeError: Object #<Object> has no method 'enter'
          at [object Object].testXShouldBeLastValueEntered (http://localhost:9876/test
/src-test/rpn_calculator_test.js:10:7)

Tests failed: Tests failed. See log for details.

src/rpn_calculator.js

var rpn_calculator = function() {
	var that = {};
	that.value = 0;
	that.x = function() {
		return that.value;
	};
	that.enter = function(value) {
		that.value = value;
	};
	return that;
};
% java -jar JsTestDriver-1.3.3d.jar --tests all --testOutput logs
..
Total 2 tests (Passed: 2; Fails: 0; Errors: 0) (0.00 ms)
  Chrome 16.0.912.75 Mac OS: Run 2 tests (Passed: 2; Fails: 0; Errors 0) (0.00 ms)
var rpn_calculator = function() {
	var that = {};
	var value = 0;
	that.value = 0;
	that.x = function() {
		return value;
	};
	that.enter = function(newValue) {
		value = newValue;
	};
	return that;
};
% java -jar JsTestDriver-1.3.3d.jar --tests all --testOutput logs
..
Total 2 tests (Passed: 2; Fails: 0; Errors: 0) (1.00 ms)
  Chrome 16.0.912.75 Mac OS: Run 2 tests (Passed: 2; Fails: 0; Errors 0) (1.00 ms)
rct = {};
rpn_calculator_test = TestCase("rpn_calculator", {
	setUp : function() {
		rct.calc = rpn_calculator();
	},
	tearDown : function() {
		rct.calc = undefined;
	}
});

rpn_calculator_test.prototype.testShouldInitiallyBe0 = function() {
	assertEquals(0, rct.calc.x());
};

rpn_calculator_test.prototype.testXShouldBeLastValueEntered = function() {
	rct.calc.enter(42);
	assertEquals(42, rct.calc.x());
};
% java -jar JsTestDriver-1.3.3d.jar --tests all --testOutput logs
..
Total 2 tests (Passed: 2; Fails: 0; Errors: 0) (1.00 ms)
  Chrome 16.0.912.75 Mac OS: Run 2 tests (Passed: 2; Fails: 0; Errors 0) (1.00 ms)

Can Handle Multiple Numbers Entered

Appended to src-test/rpn_calculator_test.js

rpn_calculator_test.prototype.testStoresMultipleValues = function() {
  rct.calc.enter(42);
  rct.calc.enter(9);
  rct.calc.drop();
  assertEquals(42, rct.calc.x());
};
% java -jar JsTestDriver-1.3.3d.jar --tests all --testOutput logs
..E
Total 3 tests (Passed: 2; Fails: 0; Errors: 1) (0.00 ms)
  Chrome 16.0.912.75 Mac OS: Run 3 tests (Passed: 2; Fails: 0; Errors 1) (0.00 ms)
    rpn_calculator.testStoresMultipleValues error (0.00 ms): TypeError: Object #<Object> 
has no method 'drop'
      TypeError: Object #<Object> has no method 'drop'
          at Object.testStoresMultipleValues (http://localhost:9876/test/src-test/
rpn_calculator_test.js:23:11)

Tests failed: Tests failed. See log for details.

src/rpn_calculator.js

var rpn_calculator = function() {
	var that = {};
	var values = [0];
	that.value = values;
	that.x = function() {
		return values[values.length-1];;
	};
	that.enter = function(newValue) {
		values.push(newValue);
	};
	that.drop = function() {
		values.pop()
	};
	return that;
};
% java -jar JsTestDriver-1.3.3d.jar --tests all --testOutput logs
...
Total 3 tests (Passed: 3; Fails: 0; Errors: 0) (1.00 ms)
  Chrome 16.0.912.75 Mac OS: Run 3 tests (Passed: 3; Fails: 0; Errors 0) (1.00 ms)

One More Check

rpn_calculator_test.prototype.testCalculatorAlwaysHasValues = function() {
  rct.calc.drop();
  rct.calc.drop();
  assertEquals(0, rct.calc.x());
};
java -jar JsTestDriver-1.3.3d.jar --tests all --testOutput logs
...F
Total 4 tests (Passed: 3; Fails: 1; Errors: 0) (1.00 ms)
  Chrome 16.0.912.75 Mac OS: Run 4 tests (Passed: 3; Fails: 1; Errors 0) (1.00 ms)
    rpn_calculator.testCalculatorAlwaysHasValues failed (0.00 ms): AssertError: expected 0 
but was [undefined]
      AssertError: expected 0 but was [undefined]
          at Object.testCalculatorAlwaysHasValues (http://localhost:9876/test/src-test/
rpn_calculator_test.js:30:2)

Update x method

  that.x = function() {
    if(values.length > 0)
      return values[values.length-1];;
    return 0;
  };

rpn_stack

rpn_stack_test.js

rpn_stack_test = TestCase("rpn_stack");

rpn_stack_test.prototype.testPopOnNewStackReturns0 = function() {
	assertEquals(0, rpn_stack().pop());
};
% java -jar JsTestDriver-1.3.3d.jar --tests all --testOutput logs
....E
Total 5 tests (Passed: 4; Fails: 0; Errors: 1) (1.00 ms)
  Chrome 16.0.912.75 Mac OS: Run 5 tests (Passed: 4; Fails: 0; Errors 1) (1.00 ms)
    rpn_stack.testPopOnNewStackReturns0 error (1.00 ms): ReferenceError: rpn_stack
 is not defined
      ReferenceError: rpn_stack is not defined
          at [object Object].testPopOnNewStackReturns0 (http://localhost:9876/test/
src-test/rpn_stack_test.js:4:18)
var rpn_stack = function() {
	that = {};
	that.pop = function() {
		return 0;
	};
	return that;
};
% java -jar JsTestDriver-1.3.3d.jar --tests all --testOutput logs
.....
Total 5 tests (Passed: 5; Fails: 0; Errors: 0) (1.00 ms)
  Chrome 16.0.912.75 Mac OS: Run 5 tests (Passed: 5; Fails: 0; Errors 0) (1.00 ms)

Append new test to rpn_stack_test.js

rpn_stack_test.prototype.testPopReturnsLastValuePushed = function() {
  var values = rpn_stack();
  values.push(42);
  assertEquals(42, values.pop());
};
var rpn_stack = function() {
  that = {};
  var values = [0];
  that.pop = function() {
    return values.pop();
  };
  that.push = function(value) {
    values.push(value);
  };
  return that;
};
......
Total 6 tests (Passed: 6; Fails: 0; Errors: 0) (0.00 ms)
  Chrome 16.0.912.75 Mac OS: Run 6 tests (Passed: 6; Fails: 0; Errors 0) (0.00 ms)
rpn_stack_test.prototype.testSeveralDropsAndPopIsStill0 = function() {
  var values = rpn_stack();
  values.drop();
  values.drop();
  values.drop();
  assertEquals(0, values.pop());
};
var rpn_stack = function() {
  that = {};
  var values = [];
  that.pop = function() {
    if(values.length > 0)
      return values.pop();
    return 0;
  };
  that.push = function(value) {
    values.push(value);
  };
  return that;
};
rpn_stack_test.prototype.testTopOfNewStack0 = function() {
  assertEquals(0, rpn_stack().top());
};
  that.top = function() {
    return 0;
  };
rpn_stack_test.prototype.testTopReturnsLastValuePushed = function() {
  var values = rpn_stack();
  values.push(19);
  assertEquals(19, values.top());
};
  that.top = function() {
    if(values.length > 0)
      return values[values.length-1];
    return 0;
  };

Using rpn_stack in rpn_calculator

var rpn_calculator = function() {
  var that = {};
  var values = rpn_stack();
  that.value = values; 
  that.x = function() {
    return values.top();
  };
  that.enter = function(newValue) {
    values.push(newValue);
  };
  that.drop = function() {
    values.pop()
  };  
  return that;
};

src/rpn_stack.js

var rpn_stack = function() {
  that = {}; 
  var values = [];
  that.pop = function() {
    if(values.length > 0)
      return values.pop();
    return 0;
  }
  that.push = function(value) {
    values.push(value);
  };
  that.top = function() {
    if(values.length > 0)
      return values[values.length-1];
    return 0;
  };
  return that;
};

Comments

" Creative Commons License
This work is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License.