【问题标题】:(MSTest) Extending ExpectedExceptionBaseAttribute hides test failure explanation(MSTest) Extending ExpectedExceptionBaseAttribute 隐藏测试失败说明
【发布时间】:2013-11-29 11:25:32
【问题描述】:

运行此测试时:

    [TestMethod]
    [ExpectedException(typeof(SpecialException))]
    public void Test1()
    {
        throw new NotImplementedException();
    }

Visual Studio 告诉我失败的原因:

测试方法 [...].Test1 抛出 异常 System.NotImplementedException,但异常 [...].SpecialException 是预期的。例外 消息:System.NotImplementedException:方法或操作是 未实施。

但是当我尝试像这样扩展ExpectedExceptionBaseAttribute(期望SpecialException中的错误代码)时:

[AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
class ExpectedSpecialException : ExpectedExceptionBaseAttribute
{
    protected override void Verify(Exception exception)
    {
        SpecialException se = exception as SpecialException;

        if (se == null)
        {
            RethrowIfAssertException(exception);

            throw new Exception("SpecialException was expected but test method threw another one");
        }
    }
}

并像这样使用它:

    [TestMethod]
    [ExpectedSpecialException]
    public void Test1()
    {
        throw new NotImplementedException();
    }

VS 产生了一条信息量不大的消息:

调用的目标已抛出异常。

我在互联网上找到的所有扩展ExpectedExceptionBaseAttribute 的示例(1,2,3)都有相同的尝试来提供有关抛出异常中失败的更多信息,但没有结果。

我做错了吗?有没有办法提供有关此类失败测试的更多信息?

【问题讨论】:

  • 该异常是由您的 Verify 方法触发的,您应该看到 InnerException 与您抛出的异常匹配。不是 MSDN 告诉你的方式,你应该使用 Assert()。

标签: c# unit-testing exception visual-studio-2012 mstest


【解决方案1】:

我认为您在问题中引用的任何帖子都没有正确实现自定义 ExpectedException 属性。我并不是说它们不是有效的解决方案,而是说它们解决了不同的问题。我认为您遇到的是一个不同的问题,这些帖子中的任何一个都没有解决。

您没有收到完整错误消息的原因似乎是 null TestContext

您可以通过查看ExpectedExceptionAttribute 的实现来验证这一点。 你可以使用反射器,你可以看到它在内部使用了TestContext。

如果看ExpectedExceptionBaseAttribute

的实现
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false,
Inherited = true)]
public abstract class ExpectedExceptionBaseAttribute : Attribute
{
     protected internal TestContext TestContext { get; internal set; }

TestContext 在运行时设置internally,不能注入到ExpectedSpecialException 属性中。 MSTest 的 ExpectedExceptionAttribute 可以访问测试运行程序内部设置的 TestContext。需要注意的是,由于 MSTest 缺乏可扩展性,我们无法真正根据需要访问和设置 TestContext。

不确定这是否会有所帮助,但您可以自定义异常并使用this 之类的方法确定引发异常的位置。我认为这是一种更好的方法。

【讨论】:

  • 指向异常的链接已失效,来自wayback machine:基本上,您不再使用属性,而是编写了一个内联断言样式的帮助器 (github),它捕获调用的代码以期望/* Act => Assert*/ ExceptionAssert.Throws(() => the code you expect to fail); 之类的异常
【解决方案2】:

经过我自己的一些研究以找到解决方案,我发现对于版本 11 (VS2012),这似乎是 VSTestIntegration dll 中的一个错误。

Microsoft.VisualStudio.TestPlatform.MSTestFramework.TestMethodRunner.HandleMethodException 方法使用反射调用调用继承的 ExpectedExceptionBaseAttribute 类而不是 ExpectedExceptionAttribute。根据MS documentation,如果“被调用的方法或构造函数抛出异常”,则返回一个TargetInvocationException,真正的异常在InnerException中。

很遗憾,HandleMethodException 在显示时并未检查消息的内部异常

调用的目标已抛出异常。

这已在版本 14 (VS2017) 中修复,可能在此之前,但我没有验证它们。该dll位于

' C:\Program Files (x86)\Microsoft Visual Studio [版本]\Common7\IDE\CommonExtensions\Microsoft\TestWindow\Extensions\Microsoft.VisualStudio.TestPlatform.Extensions.VSTestIntegration.dll

感谢@Jon-Skeet 提供pointing that out

【讨论】:

    【解决方案3】:

    对于它的价值,我只通过将断言异常传递给基本 RethrowIfAssertException 函数来解决这个问题:

    protected override void Verify(Exception exception)
    {
        if (exception is UnitTestAssertException)
        {
            RethrowIfAssertException(exception);
        }
    
        try
        {
             Assert.IsInstanceOfType<SpecialException>(exception);
        }
        catch (AssertionFailedException ex)
        {
             RethrowIfAssertException(ex);
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-01-04
      • 1970-01-01
      • 2019-10-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多