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??

Helen
  • 87,344
  • 17
  • 243
  • 314
justin.m.chase
  • 13,061
  • 8
  • 52
  • 100

2 Answers2

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(); }
        }
    };
}
Ricibald
  • 9,369
  • 7
  • 47
  • 62
  • 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? – Justin Aug 22 '11 at 14:40
  • 2
    If you're using the gui mode & nunit-gui-runner.dll, don't forget to mark your main func as [STAThread]. – Wes Mar 28 '12 at 22:37
  • I just did the second example, GUI. I had to change `"/run"` to `"-run"`. I am running on Debian Gnu/Linux. – ctrl-alt-delor Feb 10 '14 at 22:20
  • @Was Adding `[STAThread]` stopped be debugging local variable. removing it fixed this. – ctrl-alt-delor Feb 11 '14 at 12:40
  • 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? – Sergiu Jun 07 '16 at 11:19
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?

Ash
  • 60,973
  • 31
  • 151
  • 169