I am in love with test driven development (TDD) and I have a streamlined workflow for developing C# applications...
We use Visual Studio 2008 with TestDriven.net and I love the ability to right click my test project/test class and run the tests located automatically without having to leave my IDE.
Well... we're currently working on a lot of web related projects and unit testing javascript is a pain in the ass to say the least. There are frameworks out there, but I don't like them. I am not a big Not Invented Here (NIH) type guy, but I just didn't like having to run my tests from a browser... so today, I decided to solve the issue. Or at least start to solve it.
My goals were the following:
1. Leverage NUnit and TestDriven.net as much as possible to preserve IDE integration. I do not want to leave my IDE
2. Be able to unit test javascripts very easily
3. Provide easy to trace error messages.
4. Speed
Most javascript unit testing frameworks leverage the web browser and my solution is no different, I do however want this to be an integrated testing enviornment for .NET so the solution is as follows
1. I created a c# project that references the NUnit framework. I have created an abstract test class called JavascriptTest which has a [TestFixture] attribute applied. This class will serve as a base for the actual Test class which will be provided by the client. This base class contains a reference to a collection of scripts which will be run. More about this later.
JavascriptTest has a single [Test] which will be run by NUnit. When this test is run, it creates a JavascriptHost (more about this later) and passes it the scripts we want to run. the JavascriptHost class runs the scripts and returns a result which we then pass on to Nunit.
2. The JavascriptHost class is a subclass of System.Windows.Forms.Form. Upon creation it adds a WebBrowser control to it's child controls. We have marked the JavascriptHost class ComVisible so that it can interact with the WebBrowser control via window.external (this is set using the ObjectForScripting property on the WebBrowser). The host provides several callback methods that Javascript can use to call into .NET.
When the JavascriptHost's RunScripts method is called (by the JavascriptTest class) it generates a dynamic html string that is a basic page template with all of the scripts to run below the ending </body> tag. As soon as the WebBrowser is ready, it calls a javascript method called "runTests" using the InvokeScript method on the WebBrowser. The runTests method triggers the test running and javascript calls back into our host using window.external to report script errors, test passes or failures, etc.
3. To actually test this out, I created another unit test project which would be the actual test project used to test our web scripts. The unit test project has a single class called TestRunner which just inherits from JavascriptTest and has a [TestFixture] decoration. Each test is located in a javascript file in this project which is set to be an Embedded Resource. The JavascriptTest class will load these scripts at test time.
More info on the script process
Thinking about our testing process from the perspective of a webbrowser, we basically want the following to happen
1. Add a small javascript at the very beginning of the page to detect parsing errors in subsequently loaded scripts. This is important because if the client's test scripts or code scripts contain errors, we won't be able to run the tests, and we want to notify the user where exactly the errors are located.
2. Add framework scripts immediately after. Framework scripts provide the unit testing framework that the user's javascript tests will utilize. These are functions such as assert.areEqual etc.
3. Add the code scripts. Code scripts are the actual code being tested. We have to add these before we add the test scripts because the test scripts will reference the code scripts.
4. Finally, add the actual test scripts which reference both the test framework as well as the code scripts.
Our javascript unit testing framework does not add links to the script files, but actually loads the files themselves and injects their text into the test page. This makes the testing process much easier.
There is more I want to write about this, but why don't you download the code so far and take a look.
Note: You may have to fix your NUnit references. Also - you will have to change the path in the file Tester.cs to point to your js folder in the web project. This is a work in progress so the code is sloppy, but it works with TestDriven.net so I'm happy so far.