MSTest测试上下文异常处理

时间:2010-01-14 16:33:35

标签: c# unit-testing exception-handling mstest

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

如果在我的一个测试中发生未处理的异常,我想旋转exception.Data字典中的所有项目并将它们显示给测试结果,以帮助我找出测试失败的原因(我们通常会添加数据到异常以帮助我们在生产环境中调试,所以我想做同样的测试)。

注意:我没有测试异常是支持HAPPEN(我还有其他测试),我正在测试一个有效的案例,我只需要查看异常数据。

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

[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%的时间,我重新运行它通过,所以没有这些信息我无法调试任何东西。我还希望在GLOBAL级别上执行此操作,以便在任何测试失败时,我会在测试结果中获取信息,而不是为每个单独的测试执行此操作。

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

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

3 个答案:

答案 0 :(得分:3)

我一直遇到同样的问题,似乎没有对此表示支持。你甚至无法使用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/提交功能请求(或查看其他人是否已请求此功能,并添加您的投票。)

答案 1 :(得分:1)

这是一个“干净”的工作,它将把异常放入TestBase.TestContext属性(或者你想在TestBase实例中的任何地方)。

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

您要做的第一件事是创建AOP属性。这些属性定义了在异常和+ define注入条件下将要完成的操作,这是你如何做的:

/// <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;
    }
}

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

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

答案 2 :(得分:0)

如果您只是想测试预期的例外情况,可以使用ExpectedExceptionAttribute

我认为能够获得单元测试的异常会在出现意外异常时更有用,并且您希望记录或收集有关异常的额外信息,而不是依靠TestExplorer来查找检查失败测试