HY,
我正在写一个应该帮助我进行单元测试的课程。该类提供了在异常上执行断言的方法。
到目前为止,我能够编写一个方法,它接受一个没有参数且没有返回值的函数作为输入。为此,我使用System.Action - delegates。 我的班级看起来像这样:
internal static class ExceptionAssert
{
/// <summary>
/// Checks to make sure that the input delegate throws a exception of type TException.
/// <para>
/// The input delegate must be a method with no parameters and return type void!
/// </para>
/// </summary>
/// <typeparam name="TException">The type of exception expected.</typeparam>
/// <param name="methodToExecute">The method to execute.</param>
public static void Throws<TException>(Action methodToExecute) where TException : System.Exception
{
try
{
methodToExecute();
}
catch (Exception e)
{
Assert.IsTrue(e.GetType() == typeof(TException), "Expected exception of type " + typeof(TException) + " but type of " + e.GetType() + " was thrown instead.");
return;
}
Assert.Fail("Expected exception of type " + typeof(TException) + " but no exception was thrown.");
}
在单元测试中,我现在可以写:
ExceptionAssert.Throws<ArgumentNullException>(theProxy.LoadProduct,productNumber);
现在我想编写更多方法,这些方法将方法作为带参数和返回值的输入。据我所知,通用Func应该服务于此。方法签名应该是这样的:
public static void Throws<TException>(Func<T, TResult> methodToExecute, T methodArgument) where TException : System.Exception
但这不会编译。我总是要写一个像Func这样的显式类型而不是泛型。怎么了?应该可以将它声明为通用方式,因为LINQ的工作原理如下。
编辑:
宣布一切都是一个好主意,而不仅仅是一半。结果:
/// <summary>
/// Contains assertion types for exceptions that are not provided with the standard MSTest assertions.
/// </summary>
/// <typeparam name="T">The type of the input arguments.</typeparam>
/// <typeparam name="TResult">The type of the result.</typeparam>
/// <remarks>
/// The standard test framework has an Attribute called <see cref="ExpectedExceptionAttribute">ExpectedExceptionAttribute</see>. This attribute has two
/// main disadvantages:
/// <para>
/// 1. The unit test stops at the line which throws the expected exception. If you want to test a method which throws a bunch of exceptions
/// you must write a test for each exception.
/// 2. The attribute does not specify exactly where the exception has to be thrown. So if a method call earlier than expected throws
/// suddenly the same exception, the whole test is still o.k.
/// </para>
/// So this class can be used like the common assertions. You can test a method at a specific line in the test for a specific exception.
/// </remarks>
internal static class ExceptionAssert<T,TResult>
{
/// <summary>
/// Checks to make sure that the input delegate throws a exception of type TException.
/// <para>
/// The input delegate must be a method with no parameters and return type void!
/// </para>
/// </summary>
/// <typeparam name="TException">The type of exception expected.</typeparam>
/// <param name="methodToExecute">The method to execute.</param>
public static void Throws<TException>(Action methodToExecute) where TException : System.Exception
{
try
{
methodToExecute();
}
catch (Exception e)
{
Assert.IsTrue(e.GetType() == typeof(TException), "Expected exception of type " + typeof(TException) + " but type of " + e.GetType() + " was thrown instead.");
return;
}
Assert.Fail("Expected exception of type " + typeof(TException) + " but no exception was thrown.");
}
/// <summary>
/// Checks to make sure that the input delegate throws a exception of type TException with a specific exception message.
/// <para>
/// The input delegate must be a method with no parameters and return type void!
/// </para>
/// </summary>
/// <typeparam name="TException">The type of exception expected.</typeparam>
/// <param name="expectedMessage">The expected exception message.</param>
/// <param name="methodToExecute">The method to execute.</param>
/// <remarks>
/// This method asserts if the given message and the message of the thrown exception are not equal!
/// </remarks>
public static void Throws<TException>(string expectedMessage, Action methodToExecute) where TException : System.Exception
{
try
{
methodToExecute();
}
catch (Exception e)
{
Assert.IsTrue(e.GetType() == typeof(TException), "Expected exception of type " + typeof(TException) + " but type of " + e.GetType() + " was thrown instead.");
Assert.AreEqual(expectedMessage, e.Message, "Expected exception with a message of '" + expectedMessage + "' but exception with message of '" + e.Message + "' was thrown instead.");
return;
}
Assert.Fail("Expected exception of type " + typeof(TException) + " but no exception was thrown.");
}
/// <summary>
/// Checks to make sure that the input delegate throws a exception of type TException with a specific exception message.
/// <para>
/// The input delegate must be a method with ONE parameter and return type!
/// </para>
/// </summary>
/// <typeparam name="TException">The type of the exception.</typeparam>
/// <param name="methodToExecute">The method to execute.</param>
/// <param name="argument">The argument to input.</param>
public static void Throws<TException>(Func<T,TResult> methodToExecute, T argument)
where TException : System.Exception
{
try
{
methodToExecute(argument);
}
catch (Exception e)
{
Assert.IsTrue(e.GetType() == typeof(TException), "Expected exception of type " + typeof(TException) + " but type of " + e.GetType() + " was thrown instead.");
return;
}
Assert.Fail("Expected exception of type " + typeof(TException) + " but no exception was thrown.");
}
}
答案 0 :(得分:4)
你也应该“宣告”T和TResult,例如
public static void Throws<T, TResult, TException>(Func<T, TResult> methodToExecute, T methodArgument) where TException : System.Exception
否则编译器不知道T和TResult是什么。
答案 1 :(得分:1)
编译:
public static void Throws<TException, T, TResult>(Func<T, TResult> methodToExecute, T methodArgument) where TException : System.Exception
这能否为您提供所需的结果?