【问题标题】:Thrown Exception not caught in UnitTest try/catch抛出的异常未在 UnitTest try/catch 中捕获
【发布时间】:2018-07-04 16:22:23
【问题描述】:

我现在正在设计一些代码,如果字符串参数为 null 或为空,我将抛出异常,并且异常被抛出,但是当我在 UnitTesting 时它没有被捕获。

这是我正在使用的客户端。

public class PipeClient : IPipeClient
{
    public async void Send(string host, string pipeName, Message msg)
    {
        if (string.IsNullOrEmpty(msg.PreparedMessage))
            throw new ArgumentException("MESSAGE_NOT_FOUND");

        if (string.IsNullOrEmpty(host) || string.IsNullOrEmpty(pipeName))
            throw new ArgumentNullException();

        if (!host.TryParseHost()) 
            throw new ArgumentException("INVALID_HOST_NAME");

        using (var pipeClient = new NamedPipeClientStream(host, pipeName, PipeDirection.Out))
        {
            pipeClient.Connect(200);

            using (var writer = new StreamWriter(pipeClient))
            {
                await Task.Run(() => writer.WriteLine(msg.PreparedMessage));
                writer.Flush();
            }
        }
    }
}

这是单元测试

    [TestMethod]
    public void Send_FailsOnWrongHostName()
    {
        var name = "FailWithHostname";
        var msg = new Message(MyStates.Register, "UnitTest", "Test");

        try
        {
            var client = new PipeClient();
            client.Send("lol", name, msg);
        }
        catch (Exception e)
        {
            Assert.IsTrue(e is ArgumentException);
        }
    }

因此,据我所知,当我运行该测试时,它应该在我调用 Send 方法(确实如此)时抛出异常,然后在 catch 子句中被捕获,因为我没有在 PipeClient 中捕获它。然而它没有,它只是以失败的测试退出。

如果您需要更多信息,请告诉我,提前致谢。

【问题讨论】:

  • 您不需要捕获和测试异常。如果您希望发生异常,请在您的[TestMethod] 上方添加[ExpectedException(typeof(ArgumentException) 符号。
  • 我之前尝试过但没有成功,这就是我尝试这种方法的原因。我得到它没有抛出异常的错误,我不明白。
  • 我当然已经通过调试确认该方法实际上是在抛出预期的异常。
  • 好像被别的东西抓住了一样。
  • 您确定抛出的异常实际上是 ArgumentException 吗?当查看您的代码并假设确实发生了异常时,我唯一能想到的是您的 Send 方法中的某些方法调用引发了一些与 ArgumentException 不同类型的异常。

标签: c# oop exception


【解决方案1】:

我想在这个答案中提出一些问题。我不确定你的经验水平,所以请不要认为我在任何时候都居高临下。

首先是关于异步方法和任务的简要说明。

  • 除非在异步事件处理程序中,否则应避免异步 void。异步方法应返回 Task 或 Task ,否则调用方法将无法知道该方法何时完成并报告该方法是否引发了异常。 Async void 本质上是一劳永逸,没有人可以观察异常。

“在观察到的任务中,没有人可以尖叫”-Me ,2018

  • 异步方法中抛出的异常被很好地解包并抛出 当等待异步方法时,调用堆栈全部保留 并且合理明智。如果您最终不等待结果 将来某个时候你会得到一个 UnobservedTaskException 如果你没有为它配置一个全局处理程序,那将会关闭 你的申请。如果你得到一个异步方法的结果 同步使用 .Wait() 或 .Result 或通过 .GetAwaiter().GetResult() (您应该尝试避免所有 3 个,但第 3 个 如果您必须通知我,选项是最好的),那么您将 获取包装在 AggregateException 中的原始异常。

现在,如果这些对您来说都没有多大意义,我建议您阅读一下 Tasks 和 async/await。

现在开始你的测试。

您的方法是 async void,因此调用方法不会返回任何内容来表示工作或让它知道该方法已引发异常。所以它继续,测试完成,然后一切都完成,没有异常,因为 UnobservedTaskException 可以在未来的任何时候抛出(我认为这与垃圾收集器何时整理有故障的任务然后抛出有关,因为垃圾收集器是不确定的,我们不能说什么时候会发生)

那么如果你让你的异步方法返回一个任务呢???好吧,这仍然不太正确。您现在返回一个由于异常而处于故障状态的任务,但是由于您从不等待它,异常永远不会“解包”并实际抛出,因此您可以愉快地继续测试。

您需要做的是使您的测试异步并返回一个任务,并使您正在测试的方法异步任务不异步无效并在您的测试中等待该方法。

这样

[TestMethod]
public async Task Send_FailsOnWrongHostName()
{
    var name = "FailWithHostname";
    var msg = new Message(MyStates.Register, "UnitTest", "Test");

    try
    {
        var client = new PipeClient();
        await client.Send("lol", name, msg);
    }
    catch (Exception e)
    {
        Assert.IsTrue(e is ArgumentException);
    }
}

public class PipeClient : IPipeClient
{
    public async Task Send(string host, string pipeName, Message msg)
    {
        if (string.IsNullOrEmpty(msg.PreparedMessage))
            throw new ArgumentException("MESSAGE_NOT_FOUND");

        if (string.IsNullOrEmpty(host) || string.IsNullOrEmpty(pipeName))
            throw new ArgumentNullException();

        if (!host.TryParseHost()) 
            throw new ArgumentException("INVALID_HOST_NAME");

        using (var pipeClient = new NamedPipeClientStream(host, pipeName, PipeDirection.Out))
        {
            pipeClient.Connect(200);

            using (var writer = new StreamWriter(pipeClient))
            {
                await Task.Run(() => writer.WriteLine(msg.PreparedMessage));
                writer.Flush();
            }
        }
    }
}

【讨论】:

  • 首先,感谢您的详尽解释!我完全忘记了我使方法异步并在审查和重构时错过了它。这是在没有 cmets 或解释的情况下重新访问几个月前编写的代码的问题。我实际上并不知道异步 void 方法不会将异常抛回给调用者,但这是有道理的。我明天回家后会测试它,并会更新结果。再次感谢您!
猜你喜欢
  • 2018-06-05
  • 1970-01-01
  • 2020-02-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-11-09
相关资源
最近更新 更多