26 August 2006

nAnt build script to test mono web app with Ruby and Watir

Download the build script template: myWebsite.build

1. Prove nant task <csc>, <nunit2> works/doesn't work with mono

  1. Prove test assembly is fine use vsnet (.net 1.1) build, reference *.net1.1*
    nunit.framework.dll , not the mono build.

    • build asm
    • tested with nUnit2.2.0 GUI exe
    • tested with nUnit-2.2.0-mono console exe.

    Both work as expected

  2. nAnt build. nant target mono-1.0; reference lib (nunit.framework.dll) set to NUnit-2.2.0-mono

    • test assembly with nUnit2.2.0 GUI exe. On loading asm it throws exception
      'This assembly was not built with the NUNIT framework and contains no tests'
      cases' on the popout message window
    • test assembly with nUnit-2.2.0-mono
      console exe. This returns:
      OS Version: Microsoft Windows NT 5.1.2600.0 .NET Version: 1.1.4322.2032 Tests run:
      0, Failures: 0, Not run: 0, Time: 0 seconds Open the assembly by .net
      reflector, surprise, surpise there is nothing in the dll
2. Use mono mcs compiler
  1. compiles the source
    mcs -r:system.dll -r:\sslocal\Cenote.root\dependencies\NUnit-
    2.2.0-mono\bin\nunit.framework.dll -t:library SampleRubyTestFixture.cs

  2. test - test assembly with nUnit2.2.0 GUI exe. - test assembly with
    nUnit-2.2.0-mono console exe. - test assembly with nUnit2.2.8 GUI exe. All work
    as expected

  3. Open the assembly by .net reflector, it confirms that our test case is in there This confirms that nUnit2.2.* GUI exe doesn't discriminate mono build, as long as nunit.framework.dll is the .net1.1 compliance version This also confirms that the problem is not with nant task <nUnit2>, regardless which nunit build version it points to.
3. Questioning nant task <csc>
Before setting off to use task <exec> and mcs for the build, I have a few more go on task <csc>. Eventually it confirms that it was a bug in the <csc> task causes the problem.
nAnt doesn't support multiple filesets or its derived types like assemblyfileset etc, which means you cann't resuse reference assemblyfileset. For building multiple projects in a build that each project has an inter-set to others, each <csc> needs to have a full list of <reference><include> dlls. A bit of pain. Using <module> is a hack. Though it solves the resuse problem on the surface, if you poke the assembly with Reflector, you will find there are modules should really be references. this is NOT the right way to reference <assemblyfileset>.
<csc> ... <references refid="sys.assemblies " /> <modules>
<include name="${webcontrols.output.Mono}\${webcontrolsNamespace}.dll" />
<include name="${cenote.output.Mono}\${cenoteNamespace}.dll" />
</modules> </csc>

By the way, if declare <fileset>and its derived types like
<assemblyfileset> at project level(doc root) it can take an id attribue
and can be referenced from everywhere.
4. <nunit2> and nUnit2.2.x GUI
Leaving the bug in <csc> behind, I move into nant <target> unit
test with <nunit2>. nunit2 used nunit-version=""
clr-version="2.0.50727.42" for the test. Passed. However, now the mono-target
assemble is not loaded with nUnit2.2.X GUI, not even nUnit-2.2.0-mono console
exe. An System.IO.FileNotFoundException is thrown, complaining test dll or its
dependencies dlls are not found. [to-do] I will look into it later. This is not
an issue for next step. (We only use nUnit gui for vsnet build)
5. Serve web test using ruby+watir
prerequisite: install Ruby
engine and Watir library
Watir offers a clean, well define, automated and scripting (in opposite to
recording) base Web app test.
made a nice hook to integrate ruby script into nUnit test
framework. It is not absolutely necessary to integrate ruby script into nUnit.
*.rb script can run from cmd line. However, the integration leverage the
reporting function comes with nUnit.
  1. compile RubyTestExecutor- to target nunit_2.2.0_mono
  2. Write a 'Hello World' test case as well as ruby script. In Nant task
    <csc>include them as embeded resource. <resources
    dynamicprefix="true"> <include name="...\*.rb" /> </resources>
  3. VSNET .net1.1 build and nUnit GUI test

    • in vsnet reference RubyTestExecutor-
    • make sure the Web_Control_test_project is set to default web sharing. It
      contains test pages as well as test cases.
    • Postbuild action to copy test.dll and referenced dlls (except
      nUnit.framework.dll) from ~\bin\Debug to ~\bin
    • run tests

  4. VSNET mono1.0 build and nAnt build (test with <nunit2>, on my pc it picks
    the lastest nunit2.2.8 engine)

    • in nAnt build reference RubyTestExecutor-
    • compile, delpoy as usual
    • start XSP at Web_Control_test_project where pages live.
    • Both use port 80 for http request. This means we don't need to change ruby
      scripts for native 1.1 (which runs on IIS) or mono runtime (which runs XSP).
      Just need to stop/start IIS before XSP kicks start. (I argue it is more
      pragmatic then dynamic decide which port to use depends on runtime env)
5 Conclusion
With this build script, we archieve:
  • Implement, build and test ASP.Net Web Controls and Website in VSNET2003 IDE to
    target .Net 1.1 framework.
  • Use nAnt build script to link, compile, deploy the same code base to target
    Mono1.0. This build process needs to know nothing about the IDE build.
  • Use Ruby+Watir scripts to test web app in 'nearest' real way.The script test
    suite is seamlessly integrate into nUnit framework.
6 What's more can be done?
Automated XSP web server start/stop. The build process requires manually start
mono XSP web server before <nunit2> tests. XSP must run in an isolated
AppDomain/process from where nAnt is running from, so use <exec> task is
not prossible. It is also not possible to use
Application Domain
to create and load XSP into an
isolated AppDomain because on Windows OS XSP requires mono runtime environment,
which is unmanaged code. (Though XSP.exe is managed code.)

Download the build script template: myWebsite.build

Technorati Tags: nAnt