MSTest ThrowsException 与异常对象的条件?
MSTest ThrowsException with conditions on the exception object?
我正在使用 MSTest Assert.ThrowsException
,但有时我想在抛出的异常对象上添加测试条件,例如检查消息是否提到了特定的短语、标识符、数据值或其他内容。
我找到的最佳解决方案是不使用 Assert.ThrowsException
而是求助于 try...catch
的构造:
bool success = false;
try
{
// Code to be tested goes here...
success = true;
}
catch (Exception e)
{
Assert.IsInstanceOfType(e, typeof(DesiredExceptionClass));
// Tests on e go here...
}
if (success)
Assert.Fail($"Should have thrown {nameof(DesiredExceptionClass)}.");
有没有更好的方法?
使用 "better" 我的意思是更易读、更紧凑的代码,使用更少的 "boilerplate"。
我是这样使用的:
Exception exception = null;
try
{
// Code to be tested goes here...
}
catch (Exception e)
{
exception = e;
}
Assert.IsInstanceOfType(exception, typeof(DesiredExceptionClass));
有一个 来验证应该引发异常时的额外期望。
您似乎在尝试减少 "Boilerplate Code" 所以我创建了以下助手 class:
public static class ExceptionAssert
{
/// <summary>
/// Use this method if your UT is using <see cref="ExpectedExceptionAttribute"/> and you want to verify additional expectations
/// </summary>
/// <typeparam name="T">The expected exception type base</typeparam>
/// <param name="action">Execute the unit to test</param>
/// <param name="verifier">Verify the additional expectations</param>
public static void AssertException<T>(Action action, Action<T> verifier) where T: Exception
{
try
{
action();
}
catch(T e)
{
verifier(e);
throw;
}
}
/// <summary>
/// Use this method if your UT is not using <see cref="ExpectedExceptionAttribute"/> and you want to verify additional expectations
/// </summary>
/// <typeparam name="T">The expected exception type base</typeparam>
/// <param name="action">Execute the unit to test</param>
/// <param name="verifier">Verify the additional expectations</param>
/// <param name="allowDriven">Indicates if the raised exception can be an instance of driven class</param>
public static void AssertExceptionWithoutExcepctedExceptionAttribute<T>(Action action, Action<T> verifier, bool allowDriven = true) where T : Exception
{
try
{
action();
Assert.Fail("No Exception raised");
}
catch (T e)
{
if (!allowDriven && e.GetType() != typeof(T))
{
Assert.Fail($"The raised exception :: {e.GetType()} is a driven instance of :: {typeof(T)}");
}
verifier(e);
}
}
}
现在您可以按以下方式之一执行您的 UT:
[TestMethod]
[ExpectedException(typeof(Exception), AllowDerivedTypes = true)] // change the attribute settings
public void Foo()
{
// do arrange:
ExceptionAssert.AssertException<Exception>(() => // change "Exception" to the required exception type or left it as any exception
{
// do the act:
}, exception =>
{
// do you asserts statements:
});
}
[TestMethod]
public void FooBar()
{
// do arrange:
ExceptionAssert.AssertExceptionWithoutExcepctedExceptionAttribute<Exception>(() => // change "Exception" to the required exception type or left it as any exception
{
// do the act:
}, exception =>
{
// do you asserts statements:
}, false);
}
顺便说一句,IMO 你永远不应该验证异常本身,除了他的 type/driven(或者如果它是带有附加信息的自定义异常),因为你的代码永远不应该依赖于他的 MSG,调用堆栈等。 .. 我认为这就是 MS 没有添加 ExpectedExceptionAttribute 验证 MSG 的能力的原因。
我正在使用 MSTest Assert.ThrowsException
,但有时我想在抛出的异常对象上添加测试条件,例如检查消息是否提到了特定的短语、标识符、数据值或其他内容。
我找到的最佳解决方案是不使用 Assert.ThrowsException
而是求助于 try...catch
的构造:
bool success = false;
try
{
// Code to be tested goes here...
success = true;
}
catch (Exception e)
{
Assert.IsInstanceOfType(e, typeof(DesiredExceptionClass));
// Tests on e go here...
}
if (success)
Assert.Fail($"Should have thrown {nameof(DesiredExceptionClass)}.");
有没有更好的方法?
使用 "better" 我的意思是更易读、更紧凑的代码,使用更少的 "boilerplate"。
我是这样使用的:
Exception exception = null;
try
{
// Code to be tested goes here...
}
catch (Exception e)
{
exception = e;
}
Assert.IsInstanceOfType(exception, typeof(DesiredExceptionClass));
有一个
您似乎在尝试减少 "Boilerplate Code" 所以我创建了以下助手 class:
public static class ExceptionAssert
{
/// <summary>
/// Use this method if your UT is using <see cref="ExpectedExceptionAttribute"/> and you want to verify additional expectations
/// </summary>
/// <typeparam name="T">The expected exception type base</typeparam>
/// <param name="action">Execute the unit to test</param>
/// <param name="verifier">Verify the additional expectations</param>
public static void AssertException<T>(Action action, Action<T> verifier) where T: Exception
{
try
{
action();
}
catch(T e)
{
verifier(e);
throw;
}
}
/// <summary>
/// Use this method if your UT is not using <see cref="ExpectedExceptionAttribute"/> and you want to verify additional expectations
/// </summary>
/// <typeparam name="T">The expected exception type base</typeparam>
/// <param name="action">Execute the unit to test</param>
/// <param name="verifier">Verify the additional expectations</param>
/// <param name="allowDriven">Indicates if the raised exception can be an instance of driven class</param>
public static void AssertExceptionWithoutExcepctedExceptionAttribute<T>(Action action, Action<T> verifier, bool allowDriven = true) where T : Exception
{
try
{
action();
Assert.Fail("No Exception raised");
}
catch (T e)
{
if (!allowDriven && e.GetType() != typeof(T))
{
Assert.Fail($"The raised exception :: {e.GetType()} is a driven instance of :: {typeof(T)}");
}
verifier(e);
}
}
}
现在您可以按以下方式之一执行您的 UT:
[TestMethod]
[ExpectedException(typeof(Exception), AllowDerivedTypes = true)] // change the attribute settings
public void Foo()
{
// do arrange:
ExceptionAssert.AssertException<Exception>(() => // change "Exception" to the required exception type or left it as any exception
{
// do the act:
}, exception =>
{
// do you asserts statements:
});
}
[TestMethod]
public void FooBar()
{
// do arrange:
ExceptionAssert.AssertExceptionWithoutExcepctedExceptionAttribute<Exception>(() => // change "Exception" to the required exception type or left it as any exception
{
// do the act:
}, exception =>
{
// do you asserts statements:
}, false);
}
顺便说一句,IMO 你永远不应该验证异常本身,除了他的 type/driven(或者如果它是带有附加信息的自定义异常),因为你的代码永远不应该依赖于他的 MSG,调用堆栈等。 .. 我认为这就是 MS 没有添加 ExpectedExceptionAttribute 验证 MSG 的能力的原因。