A javascript unit testing framework in 50 lines

Last week at xp-man we did some TDD practise - by writing a tdd framework from scratch. The surprise was, how easy it was. So here, to my surprise, a very-bare-bones javascript unit test framework in 50 lines of code including the passing unit tests for the framework itself.

/*  www.cafe-encounter.net/p734/ */

function Specification( name, tests, outputContainer ){
    this.name= name;
    this.tests= tests;
    this.outputContainer= outputContainer || $('#testResults');
}

Specification.prototype = {
    name : 'UnnamedSpecification',
    tests : {},
    outputContainer : null,

    addMyselfToUI : function(){
        this.outputContainer.append( "<li><h3>" + this.name +"</h3><ul id='" + this.name + "'></ul></li>");
    },

    testDomId:function (test) {
        return this.name + "_" + test;
    },

    addTestToUI : function addTestToUI( test ){
        $('#' + this.name).append( "<li id='" + this.testDomId(test) + "'>" + test + "<input type='checkbox'/></li>");
    },

    markTestPassed : function( test ){
        $("#" + this.testDomId(test) + " input").prop("checked",true);
    },

    markTestFailed : function( test, ex ){
        $("#" + this.testDomId(test) + " input").prop("checked",false);
        $("#" + this.testDomId(test) + " input").after("<ul>Output:<li>" + ex.toString() + "</li></ul>");
    },

    runTest : function (test) {
        this.addTestToUI(test);
        try{
            this.tests[test]();
            this.markTestPassed(test)
        } catch(ex)  {
            this.markTestFailed(test, ex);
        }
    },

    runTests : function(){
        this.addMyselfToUI();

        for (var test in this.tests) {
            if (this.tests.hasOwnProperty(test)) this.runTest( test );
        }
    }
};

$(function(){
     new Specification("TestFrameworkSpecifications", {

        aTestShouldAddItselfInTheTestResults:function() {},

        aPassingTestShouldTickTheCheckbox : function() {},

        aFailingTestShouldUntickTheCheckbox:function () {
            throw "This thrown exception should appear in the output, indicating a failure";
        }
    }).runTests();
});

And the html doc to load and run it:

<html>
<head>
    <title>Minimal Javascript Test Framework</title>
    <script type="text/javascript" src="js/jquery-1.8.2.js"></script>
    <script type="text/javascript" src="js/wsl-testframework.js"></script>
</head>
<body>
<h1>Tests</h1>
<ul id="testResults">
</ul>
</body>
</html>

As written, I admit a dependency on jQuery, but you can replace that with document.write(). The obvious omission is a bundle of pre-defined assertions, but if you are developing a domain specific testing language then assertions should be part of that package, not part of the test running framework.

The obvious oddity is that the test suite demonstrates its test failure behaviour by failing a test; and you see that that is the correct result by inspecting the output.

This has led me to think that the TDD way to learn a new language is ... to write a TDD framework for it.

Web Forms – Mocking HttpSession

With thanks to http://stackoverflow.com/users/603670/ben-barreth
at http://stackoverflow.com/questions/1981426/how-do-i-mock-fake-the-session-object-in-asp-net-web-forms

[SetUp]
public void SetUpHttpSessionMock()
{
HttpWorkerRequest _wr = new SimpleWorkerRequest("/dummyWorkerRequest", @"c:\inetpub\wwwroot\dummy", "default.aspx", null, new StringWriter());
HttpContext.Current = new HttpContext(_wr);
HttpSessionStateContainer sessionContainer = new HttpSessionStateContainer("id", new SessionStateItemCollection(), new HttpStaticObjectsCollection(), 10, true, HttpCookieMode.AutoDetect, SessionStateMode.InProc, false);
SessionStateUtility.AddHttpSessionStateToContext(HttpContext.Current, sessionContainer);
}

Refactoring a static class with hard-coded dependencies for testability

is not that hard. You can add a factory method to the static class to create the dependency, and change the factory method at test-time.
Here's an example:

public static class WithDependencies
{
	public static string MethodWithDependencies()
	{
		using (var thing = new HardCodedThing())
		{
			return DoSomething();
		}
	}
}

which can be turned into:

public static class WithDependencies
{
    public static Func<HardCodedThing> CreateHardCodedThing = () => new HardCodedThing();

	public static void MethodWithDependencies()
	{
		using (var thing = CreateHardCodedThing())
		{
			DoSomething();
		}
	}
}

With this code in your test:

[TestFixture]
public class WhenDoingSomething
{
	private Mock<HardCodedThing> mockThing;

	[SetUp]
	public void SetUpMockThing()
	{
		// mockThing.Setup( ...  ) ... etc ...
	}

	public void Given_hardcodedthing_does_X_should_get_Y()
	{
		//Arrange
		WithDependencies.CreateHardCodedThing = () => mockThing.Object;
		//Act
		var result= WithDependencies.MethodWithDependencies();
		//Assert
		Assert.AreEqual("Y", result);
	}
}

NUnit Constraints Example – a Simple Custom Constraint

Are you short of an NUnit Assertion? You have some code for a test, but you really want it in NUnit constraint form so you can use it like any other test. They are easy to write. Here's an example which wraps a function you already wrote as a Constraint:

public class EqualsByValueConstraint : Constraint
{
	private readonly object expected;
	private CompareResult compareResult;

	public EqualsByValueConstraint(object expected)
	{
		this.expected = expected;
	}

	public override bool Matches(object actual)
	{
		this.actual = actual;
		compareResult = EqualsByValueOrFailureReason(actual, expected);
		return compareResult;
	}

	public override void WriteDescriptionTo(MessageWriter writer)
	{
		writer.WriteExpectedValue(this.expected);
	}
	public override void WriteActualValueTo(MessageWriter writer)
	{
		base.WriteActualValueTo(writer);
		writer.WriteLine();
		writer.WriteMessageLine("Compare Result " + compareResult);
	}
}
public class CompareResult
{
	public bool IsPass {get;set;}
	public string FailureDescription {get; set;}
}

If your function is just a boolean, then you could remove the CompareResult class. The drawback being that your failure message will only say 'failed' rather than give an explanation of the failure. In that case, you might just as well not use the constraint and use the Assert.That(bool, message) overload.