MSTest 测试上下文异常处理

发布于 2024-08-17 20:16:49 字数 1672 浏览 4 评论 0原文

有没有办法可以使用 TestContext 或基测试类上的其他方法来获取 MSTest 框架处理的异常?

如果我的一项测试中出现未处理的异常,我想遍历异常中的所有项目。数据字典并将它们显示到测试结果中,以帮助我找出测试失败的原因(我们通常将数据添加到异常来帮助我们在生产环境中进行调试,所以我想对测试做同样的事情)。

注意:我没有测试是否应该发生异常(我有其他测试),我正在测试一个有效的案例,我只需要查看异常数据。

这是我正在讨论的代码示例。

[TestMethod]
public void IsFinanceDeadlineDateValid()
{
    var target = new BusinessObject();
    SetupBusinessObject(target);

    //How can I capture this in the text context so I can display all the data 
    //in the exception in the test result...

    var expected = 100;
    try
    {
        Assert.AreEqual(expected, target.PerformSomeCalculationThatMayDivideByZero());
    }
    catch (Exception ex)
    {
        ex.Data.Add("SomethingImportant", "I want to see this in the test result, as its important");
        ex.Data.Add("Expected", expected);
        throw ex;
    }

}

我知道存在一些问题,为什么我可能不应该使用这样的封装方法,但我们也有子测试来测试 PerformSomeCalculation 的所有功能...

但是,如果测试失败,99% 的情况下,我会重新运行它通过,所以如果没有这些信息我就无法调试任何东西。我还想在全局级别上执行此操作,以便如果任何测试失败,我都会在测试结果中获取信息,而不是为每个单独的测试执行此操作。

以下是将异常信息放入测试结果中的代码。

    public void AddDataFromExceptionToResults(Exception ex)
    {
        StringBuilder whereAmI = new StringBuilder();
        var holdException = ex;
        while (holdException != null)
        {
            Console.WriteLine(whereAmI.ToString() + "--" + holdException.Message);
            foreach (var item in holdException.Data.Keys)
            {
                Console.WriteLine(whereAmI.ToString() + "--Data--" + item + ":" + holdException.Data[item]);
            }

            holdException = holdException.InnerException;
        }
    }

Is there a way that I can get to the exception that was handled by the MSTest framework using the TestContext or some other method on a base test class?

If an unhandled exception occurs in one of my tests, I'd like to spin through all the items in the exception.Data dictionary and display them to the test result to help me figure out why the test failed (we usually add data to the exception to help us debug in the production env, so I'd like to do the same for testing).

Note: I am not testing that an exception was SUPPOSED TO HAPPEN (I have other tests for that), I am testing a valid case, I just need to see the exception data.

Here is a code example of what I'm talking about.

[TestMethod]
public void IsFinanceDeadlineDateValid()
{
    var target = new BusinessObject();
    SetupBusinessObject(target);

    //How can I capture this in the text context so I can display all the data 
    //in the exception in the test result...

    var expected = 100;
    try
    {
        Assert.AreEqual(expected, target.PerformSomeCalculationThatMayDivideByZero());
    }
    catch (Exception ex)
    {
        ex.Data.Add("SomethingImportant", "I want to see this in the test result, as its important");
        ex.Data.Add("Expected", expected);
        throw ex;
    }

}

I understand there are issues around why I probably shouldn't have such an encapsulating method, but we also have sub tests to test all the functionality of PerformSomeCalculation...

However, if the test fails, 99% of the time, I rerun it passes, so I can't debug anything without this information. I would also like to do this on a GLOBAL level, so that if any test fails, I get the information in the test results, as opposed to doing it for each individual test.

Here is the code that would put the exception info in the test results.

    public void AddDataFromExceptionToResults(Exception ex)
    {
        StringBuilder whereAmI = new StringBuilder();
        var holdException = ex;
        while (holdException != null)
        {
            Console.WriteLine(whereAmI.ToString() + "--" + holdException.Message);
            foreach (var item in holdException.Data.Keys)
            {
                Console.WriteLine(whereAmI.ToString() + "--Data--" + item + ":" + holdException.Data[item]);
            }

            holdException = holdException.InnerException;
        }
    }

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

渔村楼浪 2024-08-24 20:16:49

我遇到了同样的问题,似乎没有对此的支持。您甚至不能使用 ApplicationDomain 的未处理异常挂钩,因为如果 MSTEST 在异常冒出那么远之前没有捕获异常,它本身就会崩溃。

可能的解决方法:

    private delegate void TestImplDelegate();

    private void RunTestWithExceptionLogging(TestImplDelegate testImpl)
    {
        try
        {
            testImpl();
        }
        catch (Exception e)
        {
            string message = e.Message; // don't warn about unused variables

            // do logging here
        }
    }

    [TestMethod]
    public void test1()
    {
        RunTestWithExceptionLogging(test1Impl);
    }
    private void test1Impl()
    {
        // test code goes here

        throw new Exception("This should get logged by the test wrapper.");
    }

    [TestMethod]
    public void test2()
    {
        RunTestWithExceptionLogging(test2Impl);
    }
    private void test2Impl()
    {
        // test code goes here

        throw new Exception("This should get logged by the test wrapper.");
    }

这当然不是最佳的,但至少这样您就不会拥有异常处理程序代码的多个副本。

我建议在 http://connect.microsoft.com/ 提交功能请求(或参阅如果其他人已经提出请求,请添加您的投票。)

I've been running into the same issue, there doesn't seem to be support for this. You can't even use ApplicationDomain's unhandled exception hook since if MSTEST didn't catch exceptions before they bubbled up that far, it would itself crash.

Possible workaround:

    private delegate void TestImplDelegate();

    private void RunTestWithExceptionLogging(TestImplDelegate testImpl)
    {
        try
        {
            testImpl();
        }
        catch (Exception e)
        {
            string message = e.Message; // don't warn about unused variables

            // do logging here
        }
    }

    [TestMethod]
    public void test1()
    {
        RunTestWithExceptionLogging(test1Impl);
    }
    private void test1Impl()
    {
        // test code goes here

        throw new Exception("This should get logged by the test wrapper.");
    }

    [TestMethod]
    public void test2()
    {
        RunTestWithExceptionLogging(test2Impl);
    }
    private void test2Impl()
    {
        // test code goes here

        throw new Exception("This should get logged by the test wrapper.");
    }

It's certainly not optimal, but at least this way you don't have multiple copies of the exception handler code.

I would recommend filing a feature request for this at http://connect.microsoft.com/ (or see if someone else has already requested it, and add your vote.)

杀手六號 2024-08-24 20:16:49

这是一个“干净”的解决方法,它将异常放入 TestBase.TestContext 属性中(或 TestBase 实例中您想要的任何位置)。

该示例使用 postsharp (这是一个 AOP 库)在编译时将 try-catch 注入到代码中。它将注入所有具有 [TestMethod] 属性的方法。 - postsharp 免费版可以完成这项工作,无需许可证。

您要做的第一件事是创建 AOP 属性。属性定义了发生异常时要执行的操作,并定义了注入条件,这就是您的操作方式:

/// <summary>
/// Catch exceptions of tests and save them in <see cref="TestBase"/> under TestContext.Properties. This is done since MSTEST does not supply any mechanism to catch tests exceptions.
/// </summary>
[SerializableAttribute]
public class CodedTestsExceptionsHandlingAop : OnExceptionAspect
{
    /// <summary>
    /// The name of the property that will be added to the test context properties object.
    /// </summary>
    public const string FailureExceptionProerty = "FailureException";

    /// <summary>
    /// Save the exception in a <see cref="TestBase"/> and rethrow.
    /// </summary>
    /// <param name="args"></param>
    public override void OnException(MethodExecutionArgs args)
    {
        var testBase = (Framework.TestBase) args.Instance;//The instance running the test inherits from TestBase.
        testBase.TestContext.Properties.Add("FailureException", args.Exception);

        args.FlowBehavior = FlowBehavior.RethrowException;
    }

    /// <summary>
    /// Make sure only test methods will get this AOP.
    /// </summary>
    /// <param name="method"></param>
    /// <returns></returns>
    public override bool CompileTimeValidate(MethodBase method)
    {
        if (method.IsDefined(typeof(TestMethodAttribute)))
            return true;

        return false;
    }
}

第二件事,您必须将以下程序集级别属性添加到您的测试项目中(还需要有 postsharp如果它与 TestBase 不在同一个项目中,则已安装),这将在测试程序集上应用 AOP 注入:

[assembly: CodedTestsExceptionsHandlingAop(AttributeTargetTypes = "*", AttributeTargetElements = MulticastTargets.Method)]

Here is a "clean" work around which will put the exception into a TestBase.TestContext property (or wherever you want in your TestBase instance).

The example uses postsharp (Which is an AOP lib) to inject try-catch to your code in compile time. It will inject to all methods which has [TestMethod] attribute. - the postsharp free edition will do the work, no need to by a license.

1st thing you have to do is creating the AOP attribute. The attributes defines what will be done in case of exception and + define conditions for injecting, this is how you do it:

/// <summary>
/// Catch exceptions of tests and save them in <see cref="TestBase"/> under TestContext.Properties. This is done since MSTEST does not supply any mechanism to catch tests exceptions.
/// </summary>
[SerializableAttribute]
public class CodedTestsExceptionsHandlingAop : OnExceptionAspect
{
    /// <summary>
    /// The name of the property that will be added to the test context properties object.
    /// </summary>
    public const string FailureExceptionProerty = "FailureException";

    /// <summary>
    /// Save the exception in a <see cref="TestBase"/> and rethrow.
    /// </summary>
    /// <param name="args"></param>
    public override void OnException(MethodExecutionArgs args)
    {
        var testBase = (Framework.TestBase) args.Instance;//The instance running the test inherits from TestBase.
        testBase.TestContext.Properties.Add("FailureException", args.Exception);

        args.FlowBehavior = FlowBehavior.RethrowException;
    }

    /// <summary>
    /// Make sure only test methods will get this AOP.
    /// </summary>
    /// <param name="method"></param>
    /// <returns></returns>
    public override bool CompileTimeValidate(MethodBase method)
    {
        if (method.IsDefined(typeof(TestMethodAttribute)))
            return true;

        return false;
    }
}

2nd thing, you'll have to add the following assembly level attribute to your tests project (which also need to have postsharp installed if it is not in the same project as your TestBase), this will apply the AOP injection over the tests assembly:

[assembly: CodedTestsExceptionsHandlingAop(AttributeTargetTypes = "*", AttributeTargetElements = MulticastTargets.Method)]
想你只要分分秒秒 2024-08-24 20:16:49

如果您只是想测试预期的异常,您可以使用 ExpectedExceptionAttribute

我认为,当它是意外异常并且您想要记录或收集有关异常的额外信息时,能够获取单元测试的异常会更有用,而不是依赖于TestExplorer 用于查找检查失败的测试。

If you're just wanting to test expected exceptions you could use the ExpectedExceptionAttribute

I would think being able to get the exception for a unit test would be more useful when it is an unexpected exception and you want to log or gather extra information about the exception, rather than relying on the TestExplorer to find an examine failed tests.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文