How to run NUnit programmatically
Asked Answered
K

2

18

I have some assembly that references NUnit and creates a single test class with a single test method. I am able to get the file system path to this assembly (e.g. "C:...\test.dll"). I would like to programmatically use NUnit to run against this assembly.

So far I have:

var runner = new SimpleTestRunner();
runner.Load(path);
var result = runner.Run(NullListener.NULL);

However, calling runner.Load(path) throws a FileNotFound exception. I can see through the stack trace that the problem is with NUnit calling Assembly.Load(path) down the stack. If I change path to be something like "Test, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" then I still get the same error.

I have added an event handler to AppDomain.Current.AssemblyResolve to see if I could manually resolve this type but my handler never gets called.

What is the secret to getting Assembly.Load(...) to work??

Kinetics answered 12/10, 2008 at 3:35 Comment(1)
In the end my solution was to just use XUnit. NUnit is kind of crufty.Kinetics
C
29

If you want to open in a console mode, add nunit-console-runner.dll reference and use:

NUnit.ConsoleRunner.Runner.Main(new string[]
   {
      System.Reflection.Assembly.GetExecutingAssembly().Location, 
   });

If you want to open in a gui mode, add nunit-gui-runner.dll reference and use:

NUnit.Gui.AppEntry.Main(new string[]
   {
      System.Reflection.Assembly.GetExecutingAssembly().Location, 
      "/run"
   });

This is the best approach because you don't have to specify any path.

Another option is also to integrate NUnit runner in Visual Studio debugger output:

public static void Main()
{
    var assembly = Assembly.GetExecutingAssembly().FullName;
    new TextUI (new DebugTextWriter()).Execute(new[] { assembly, "-wait" });
}

public class DebugTextWriter : StreamWriter
{
    public DebugTextWriter()
        : base(new DebugOutStream(), Encoding.Unicode, 1024)
    {
        this.AutoFlush = true;
    }

    class DebugOutStream : Stream
    {
        public override void Write(byte[] buffer, int offset, int count)
        {
            Debug.Write(Encoding.Unicode.GetString(buffer, offset, count));
        }

        public override bool CanRead { get { return false; } }
        public override bool CanSeek { get { return false; } }
        public override bool CanWrite { get { return true; } }
        public override void Flush() { Debug.Flush(); }
        public override long Length { get { throw new InvalidOperationException(); } }
        public override int Read(byte[] buffer, int offset, int count) { throw new InvalidOperationException(); }
        public override long Seek(long offset, SeekOrigin origin) { throw new InvalidOperationException(); }
        public override void SetLength(long value) { throw new InvalidOperationException(); }
        public override long Position
        {
            get { throw new InvalidOperationException(); }
            set { throw new InvalidOperationException(); }
        }
    };
}
Carolacarolan answered 16/1, 2009 at 10:58 Comment(5)
I tried this approach and it gives an "Object reference not set to an instance of an object." when calling Main. Perhaps different args are expected now?Gingras
If you're using the gui mode & nunit-gui-runner.dll, don't forget to mark your main func as [STAThread].Ellissa
I just did the second example, GUI. I had to change "/run" to "-run". I am running on Debian Gnu/Linux.Vinculum
@Was Adding [STAThread] stopped be debugging local variable. removing it fixed this.Vinculum
Hello, when I try to open the gui mode and I use code from your example, I have the following problem: first run ok, second run I get the error: "Object not set to an instance of an object". Analyzing the stack trace I founded that this error is raised inside nunit code. May be I should clean something after show the gui runner?Dinsmore
G
3

"What is the secret to getting Assembly.Load to work?"

System.Reflection.Assembly.Load takes an string containing an assembly name, not a path to a file.

If you want to load an assembly from a file use:

Assembly a = System.Reflection.Assembly.LoadFrom(pathToFileOnDisk);

(LoadFrom actually uses Assembly.Load internally)

By the way, is there any reason why you can;t use the NUnit-Console command line tool and just pass it the path to your test assembly? You could then just use the System.Diagnostics.Process to run this from within your client application, might be simpler?

Gentleman answered 12/10, 2008 at 3:47 Comment(3)
Well I wish I could use LoadFrom but unfortunately the Assembly.Load is being called from within NUnit not my code so I can't control it.Kinetics
I probably will need to just call it through a process like you suggest... I would rather have objects for my own display purposes but it should be good enough to just use a process for now.Kinetics
There are no 'secrets' in programming!Reinhart

© 2022 - 2024 — McMap. All rights reserved.