[Mono-list] Nunit on Linux

Martin Baulig martin@gnome.org
26 Feb 2002 22:05:15 +0100


--=-=-=

"Nick Drochak" <ndrochak@gol.com> writes:

> For the tests to be of any practical use anymore, we must get Nunit
> running on Linux.  There are internal calls sprinkled throught the
> corlib now that basically make it impossible to test the corlib on
> windows.  Well, we could get mono to build and work on Windows as
> another option, but that's the easy way out :)

Hi,

I looked at this a bit this afternoon and I think the biggest job is
to get System.Reflection fully working - NUnit heavily uses dynamic
method invocations and they aren't implemented yet.

For the meantime, one way to test things on Linux is to use a custom
testrunner which calls all the tests statically.

Here's a small HOWTO:

* first of all, you need to write your own testrunner - the following
  is a good start:

  
--=-=-=
Content-Type: application/octet-stream
Content-Disposition: attachment; filename=RunTests.cs

using System;
using System.IO;
using System.Threading;
using System.Globalization;

using NUnit.Framework;

class MainApp {

	static TextWriter fWriter = Console.Out;

	protected static TextWriter Writer {
		get { return fWriter; }
	}

	public static void Print(TestResult result) {
		PrintErrors(result);
		PrintFailures(result);
		PrintHeader(result);
	}

	/// <summary>Prints the errors to the standard output.</summary>
	public static void PrintErrors(TestResult result) {
		if (result.ErrorCount != 0) {
			if (result.ErrorCount == 1)
				Writer.WriteLine("There was "+result.ErrorCount+" error:");
			else
				Writer.WriteLine("There were "+result.ErrorCount+" errors:");
			
			int i= 1;
			foreach (TestFailure failure in result.Errors) {
				Writer.WriteLine(i++ + ") "+failure+"("+failure.ThrownException.GetType().ToString()+")");
				Writer.Write(failure.ThrownException);
			}
		}
	}

	/// <summary>Prints failures to the standard output.</summary>
	public static void PrintFailures(TestResult result) {
		if (result.FailureCount != 0) {
			if (result.FailureCount == 1)
				Writer.WriteLine("There was " + result.FailureCount + " failure:");
			else
				Writer.WriteLine("There were " + result.FailureCount + " failures:");
			int i = 1;
			foreach (TestFailure failure in result.Failures) {
				Writer.Write(i++ + ") " + failure.FailedTest);
				Exception t= failure.ThrownException;
				if (t.Message != "")
					Writer.WriteLine(" \"" + t.Message + "\"");
				else {
					Writer.WriteLine();
					Writer.Write(failure.ThrownException);
				}
			}
		}
	}

	/// <summary>Prints the header of the report.</summary>
	public static void PrintHeader(TestResult result) {
		if (result.WasSuccessful) {
			Writer.WriteLine();
			Writer.Write("OK");
			Writer.WriteLine (" (" + result.RunCount + " tests)");
			
		} else {
			Writer.WriteLine();
			Writer.WriteLine("FAILURES!!!");
			Writer.WriteLine("Tests Run: "+result.RunCount+ 
					 ", Failures: "+result.FailureCount+
					 ", Errors: "+result.ErrorCount);
		}
	}

 	public static void Main() {

		Thread.CurrentThread.CurrentCulture = new CultureInfo ("en-US");

		TestResult result = new TestResult ();
		TestSuite suite = new TestSuite ();
		suite.AddTest (new MonoTests.System.DateTimeTest ("DateTimeTest"));
		suite.AddTest (new MonoTests.System.TimeZoneTest ("TimeZoneTest"));
		suite.Run (result);
		Print (result);
	}
}

--=-=-=


* in your test file (let's use DateTimeTest.cs for an example), you need
  to override the RunTests method:

=====
        public DateTimeTest (string name): base(name) {}

	public static ITest Suite
	{
		get {
			TestSuite suite = new TestSuite ();
			return suite;
		}
	}

	protected override void RunTest ()
	{
        	TestCtors ();
		TestToString ();
		TestParseExact ();
		TestParse ();
	}
====

  You need to manually list all your tests there ....

* you need to reference your test suite in the RunTests.cs - if you look at the end of the
  attached RunTests.cs, there is:

====
 	public static void Main() {

		Thread.CurrentThread.CurrentCulture = new CultureInfo ("en-US");

		TestResult result = new TestResult ();
		TestSuite suite = new TestSuite ();
		suite.AddTest (new MonoTests.System.DateTimeTest ("DateTimeTest"));
		suite.AddTest (new MonoTests.System.TimeZoneTest ("TimeZoneTest"));
		suite.Run (result);
		Print (result);
	}
===

  Add all your test suites there.

* manually compile RunTests.cs and your test suites to an executable RunTests.exe:
  (you need to do this on Windows, but see below)

    csc /nologo /lib:c:/cygwin/usr/local/martin/bin /r:NUnitCore.dll RunTests.cs DateTimeTest.cs
        TimeZoneTest.cs

* run the RunTests.exe with mint or mono

If you're doing stuff on Linux and need to quickly run a command on Windows, here are two shell
scripts which proved useful for me:

  - put this in your $PATH on your Linux box and make csc a symlink to it


--=-=-=
Content-Type: application/octet-stream
Content-Disposition: attachment; filename=atlantis

#!/usr/bin/perl -w

$LINUXPREFIX = '/home/export/martin';
$WINPREFIX   = '//townsville/martin';

$dir = `pwd`; chop $dir;
$dir =~ s/^$LINUXPREFIX/$WINPREFIX/ or die
    "Can't map directory `$dir' to windows path";

$0 =~ m,.*/(.*)$, or die
    "Can't map command name `$0' to windows path";
$command = $1;

@args = @ARGV;
unshift @args, $command unless $command eq 'atlantis';

system ("ssh", "atlantis", "-l", "martin", "/usr/local/bin/atlantis", $dir, @args);

--=-=-=


 - put this in your $PATH on your Windows box


--=-=-=
Content-Type: application/octet-stream
Content-Disposition: attachment; filename=atlantis

#!/bin/sh

dir=$1 ; shift
cd $dir && $@

--=-=-=


I'm using a partition which is shared between Linux (/home/export/martin) and Windows (//townsville/martin);
the script automatically translates the path names, so you can just type 'csc' on Linux and it ssh's to
Windows and runs it there.

-- 
Martin Baulig
martin@gnome.org

--=-=-=--