如何在C#控制台应用程序中进行单元测试(Nunit)的Main方法?

17

我对在控制台应用程序中进行Main方法的单元测试有疑问。标准签名是:

  public static void Main(string[] args)

我希望能够测试以确保只传递了1个参数。如果传递了多个参数,我希望测试失败。

我认为我无法使用MOQ模拟它,因为这是一个静态方法。

有没有人有相关的经验?

有什么想法吗?

谢谢。


你为什么需要模拟它?它是否有无法调用的依赖项? - Davin Tryon
在主方法中运行时检查输入是非常关键的,这对于单元测试来说为什么很重要呢? - SBI
给未来的读者一个提示:签名可以改为static int Main,我有时会利用返回信号来创建单元测试。 - Simeon
2个回答

29

在您的情况下,没有任何可嘲笑的地方。静态Program.Main方法与其他方法一样,您可以像调用其他方法一样测试它-通过调用它。

static void方法的问题在于,您只能验证它是否抛出异常或与输入参数(或其他静态成员)交互。由于在string[]上没有任何要交互的内容,您只能测试前者情况。

然而,更加可靠的方法是将Main中包含的所有逻辑委托给单独的组件并对其进行测试。这不仅可以彻底测试您的输入参数处理逻辑,还可以将Main简化为以下形式:

public static void Main(string[] args)
{
    var bootstrapper = new Bootstrapper();
    bootstrapper.Start(args);
}

有没有不需要重构代码就能实现这个的方法? - choudhury smrutiranjan parida
1
你能测试引导程序是否被正确调用吗?假设动机是代码覆盖率指标。 - MikeF

1

集成测试

ProgramTest.cs

using NUnit.Framework;

namespace Tests;

public class ConsoleTests
{
    [Test]
    public void ProhibitsMoreThanOneArgument()
    {
        var capturedStdOut = CapturedStdOut(() =>
        {
            RunApp(arguments: new string[] { "argument1", "argument2" });
        });

        Assert.AreEqual("Passing two arguments is not supported.", capturedStdOut );
    }

    void RunApp(string[]? arguments = default)
    {
        var entryPoint = typeof(Program).Assembly.EntryPoint!;
        entryPoint.Invoke(null, new object[] { arguments ?? Array.Empty<string>() });
    }

    string CapturedStdOut(Action callback)
    {
        TextWriter originalStdOut = Console.Out;

        using var newStdOut = new StringWriter();
        Console.SetOut(newStdOut);

        callback.Invoke();
        var capturedOutput = newStdOut.ToString();

        Console.SetOut(originalStdOut);

        return capturedOutput;
    }
}

实现

Program.cs

if (args.Length > 1)
{
    Console.WriteLine("Passing two arguments is not supported.");
}

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