我正在编写一个小包装器(MyWrapper
),用于单元测试。它的目的是用try-catch包装测试代码,以便捕获一个特定的异常(MySpecialException
),然后忽略测试。
为什么我这样做不应与此问题相关。
根据以下代码,如何阻止其他人传递Action
并使用async这样?
或换句话说:如何强制他们使用MyWrapper.ExecuteAsync(Func<Task>)
?
using System;
using System.Threading.Tasks;
using NUnit.Framework;
namespace PreventAsyncActionLambdaExample
{
[TestFixture]
public class Example
{
[Test]
public async Task ExampleTest()
{
// How do I prevent others from passing an action and using async like this?
// Or in other words: How do I force them to use MyWrapper.ExecuteAsync(Func<Task>) instead?
MyWrapper.Execute(async () =>
{
var cut = new ClassUnderTest();
await cut.DoSomethingAsync();
Assert.Fail("Problem: This line will never be reached");
});
}
}
public static class MyWrapper
{
// This method SHOULD NOT, BUT WILL be used in this example
public static void Execute(Action action)
{
try
{
action();
}
catch (MySpecialException)
{
Assert.Ignore("Ignored due to MySpecialException");
}
}
// This method SHOULD BE USED in this example, BUT WILL NOT be used.
public static async Task ExecuteAsync(Func<Task> func)
{
try
{
await func();
}
catch (MySpecialException)
{
Assert.Ignore("Ignored due to MySpecialException");
}
}
}
public class MySpecialException : Exception
{
// This is another exception in reality which is not relevant for this example
}
public class ClassUnderTest
{
public Task DoSomethingAsync()
{
return Task.Delay(20); // Simulate some work
}
}
}
答案 0 :(得分:2)
我担心你在编译时无法真正阻止它,但你可以编写另一个重载,在这种情况下会被提取,告诉他们应该使用ExecuteAsync
代替: / p>
public static Task Execute(Func<Task> action)
{
throw new Exception("Please use the ExecuteAsync(Func<Task> func) method instead if you will be passing async lambdas");
}
答案 1 :(得分:1)
正如其他答案所述,我认为你不能在编译时阻止它。但是,您可以执行hacky解决方法并抛出异常。灵感来自this answer。它可能不是一个好的解决方案,但它至少可以使测试失败。
public static bool IsThisAsync(Action action)
{
return action.Method.IsDefined(typeof(AsyncStateMachineAttribute),
false);
}
// This method SHOULD NOT, BUT WILL be used in this example
public static void Execute(Action action)
{
try
{
if (IsThisAsync(action))
{
Console.WriteLine("Is async");
throw new ArgumentException("Action cannot be async.", nameof(action));
}
else
{
Console.WriteLine("Is not async");
}
action();
}
catch (MySpecialException)
{
}
}
测试:
[TestClass]
public class MyWrapperTests
{
// Will not pass
[TestMethod]
public void ShouldAllowAsyncAction()
{
// This will throw an exception
MyWrapper.Execute(async () =>
{
Assert.IsTrue(true);
await Task.Run(() =>
{
Console.WriteLine("Kind of async");
});
});
}
// Will pass, since ArgumentException is expected.
[TestMethod]
[ExpectedException(typeof(ArgumentException))]
public void ShouldThrowArgumentExceptionWhenAsync()
{
// This will throw an exception. But that's expected.
MyWrapper.Execute(async () =>
{
Assert.IsTrue(true);
await Task.Run(() =>
{
Console.WriteLine("Kind of async");
});
});
}
// Passes
[TestMethod]
public void ShouldAllowSyncAction()
{
MyWrapper.Execute(() =>
{
Assert.IsTrue(true);
});
}
}