如何在程序中以编程方式运行NUnit

18

我有一些汇编代码需要引用NUnit,并创建一个包含单个测试方法的测试类。我能够获得该程序集的文件系统路径(例如“C:... \test.dll”)。我希望能够通过编程方式使用NUnit来针对这个程序集运行测试。

到目前为止,我已经实现了:

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

然而,调用runner.Load(path)会抛出一个FileNotFound异常。我可以通过堆栈跟踪看到问题在于NUnit在堆栈中向下调用了Assembly.Load(path)。如果我将path更改为类似于“Test,Version=1.0.0.0,Culture=neutral,PublicKeyToken=null”的内容,那么我仍然会得到相同的错误。

我已经向AppDomain.Current.AssemblyResolve添加了一个事件处理程序,以查看是否可以手动解析此类型,但我的处理程序从未被调用。

如何让Assembly.Load(...)正常工作?


最终我的解决方案是只使用XUnit。NUnit有点过时了。 - justin.m.chase
2个回答

29

如果想在控制台模式下运行,请添加nunit-console-runner.dll引用,并使用以下命令:

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, 
   });
如果您想以GUI模式打开,添加nunit-gui-runner.dll引用并使用:
NUnit.Gui.AppEntry.Main(new string[]
   {
      System.Reflection.Assembly.GetExecutingAssembly().Location, 
      "/run"
   });

这是最好的方法,因为您不需要指定任何路径。

另一种选择是将NUnit运行器集成到Visual Studio调试器输出中:

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(); }
        }
    };
}

我尝试了这种方法,但在调用Main时出现了“对象引用未设置为对象的实例”。也许现在需要不同的参数? - Justin
2
如果您正在使用GUI模式和nunit-gui-runner.dll,请不要忘记将您的主函数标记为[STAThread]。 - Wes
我刚刚完成了第二个例子,GUI。我不得不将“/run”改为“-run”。我正在Debian Gnu/Linux上运行。 - ctrl-alt-delor
添加 [STAThread] 后,我的本地变量无法调试。将其删除后问题得到解决。 - ctrl-alt-delor
你好,当我尝试打开GUI模式并使用您的示例代码时,我遇到了以下问题:第一次运行正常,第二次运行时出现错误:“对象未设置为对象的实例”。分析堆栈跟踪,我发现这个错误是在nunit代码内部引发的。也许我应该在显示GUI运行器后清理一些东西? - Sergiu

3

如何让Assembly.Load正常工作?

System.Reflection.Assembly.Load需要一个字符串类型的程序集名称,而不是文件路径。

如果你想从文件中加载程序集,请使用:

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

(LoadFrom实际上在内部使用Assembly.Load)

顺便问一下,你不能使用NUnit-Console命令行工具并只传递测试程序集的路径吗?然后你可以使用System.Diagnostics.Process从客户端应用程序运行它,这可能更简单?


我很希望能够使用LoadFrom,但不幸的是Assembly.Load被NUnit调用而非我的代码,因此我无法控制它。 - justin.m.chase
我可能只需要像你建议的那样通过进程来调用它...虽然我更喜欢为自己的显示目的使用对象,但现在仅使用进程应该已经足够了。 - justin.m.chase
编程中没有“秘密”! - Marcel Valdez Orozco

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接