繁体   English   中英

异步方法中的单元测试异常

[英]Unit testing exception in async method

我正在尝试使用 VSTest 对下面的异步方法进行单元测试。 但是,即使仅在第一种情况下抛出异常, AsyncMathsStatic.Divide(4, 0)AsyncMathsStatic.Divide(4, 1))也通过了。

[TestClass]
public class UnitTest1
{
    [TestMethod]

    public void DivideTest1()
    {
        // Func<Task> action = async()=> {  AsyncMathsStatic.Divide(4, 0); };
        //action.Should().Throw<DivideByZeroException>();

        Assert.ThrowsExceptionAsync<DivideByZeroException>(async () => 
        AsyncMathsStatic.Divide(4, 0));
    }
}

public class AsyncMathsStatic
{
    public static async void Divide(int v1, int v2)
    {
        try
        {
            if (v1/v2 > 1)
            {
                // do something time consuming
            }   
        }
        catch (DivideByZeroException ex)
        {
            throw;
        }
    }
}

了解异步方法的工作原理很重要,以了解这里发生了什么。 所有异步方法都开始同步运行,就像任何其他方法一样。 但是在第一次作用于未完成Task await该方法返回 通常它会返回自己的Task ,然后调用者可以等待。

但是如果方法签名是async void ,那么它什么都不返回。 此时,该方法还没有完成运行,但调用方法永远不会知道它何时或是否完成。

这很可能就是这里发生的事情。 该方法在遇到第一个await并认为测试成功完成时返回。 它永远不会看到稍后抛出的异常。

解决方法是返回一个Task ,因此可以等待该方法:

public static async Task Divide(int v1, int v2)

async void的唯一合法用途是用于事件处理程序,因为您别无选择,只能使它们void 但在那里通常也可以,因为事件应该是“哦,顺便说一下”,并且事件处理程序的成功完成通常不会影响调用它的任何内容的进一步操作(但也有一些例外) .

如果您的测试环境不允许使用异步测试方法,请使用以下内容:

       [TestMethod]
    public void TestMethod1()
    {
        Task.Run(async () =>
        {
           // test setup

            var result = await SomeAsyncTask();
            Assert.IsTrue(result.Id != 0, "Id not changed");

        }).GetAwaiter().GetResult();
    }

正如@Paulo 所指出的,如果您的测试环境确实允许异步测试方法,那么您可以使用:

      [TestMethod]
    public async Task TestMethod1()
    {
       // test setup

        var result = await SomeAsyncMethod();
        Assert.IsTrue(result.Id != 0, "Id not changed");
    }

即使该方法是同步的,执行也将始终同步,直到第一次等待未完成的任务。 你的代码甚至没有await s。

async void方法是不可等待的。

一个未等待的任务由一个方法返回,就好像该方法是一个async void

以下代码显示了所有这些情况:

static async Task Main()
{
    try
    {
        Console.WriteLine("Before calling "+ nameof(AsyncMathsStatic.Divide1));
        var t = AsyncMathsStatic.Divide1(4, 0);
        Console.WriteLine("After calling "+ nameof(AsyncMathsStatic.Divide1));
        await t;
    }
    catch (DivideByZeroException ex)
    {
        Console.WriteLine("Exception thrown in " + nameof(Main));
    }

    try
    {
        Console.WriteLine("Before calling "+ nameof(AsyncMathsStatic.Divide2));
        var t = AsyncMathsStatic.Divide2(4, 0);
        Console.WriteLine("After calling "+ nameof(AsyncMathsStatic.Divide2));
        await t;
    }
    catch (DivideByZeroException ex)
    {
        Console.WriteLine("Exception thrown in " + nameof(Main));
    }
}

public class AsyncMathsStatic
{
    public static async Task Divide1(int v1, int v2)
    {
        try
        {
            Console.WriteLine(nameof(Divide1) + ".1");
            await Task.Yield();
            Console.WriteLine(nameof(Divide1) + ".2");
            if (v1 / v2 > 1)
            {
                await Task.Yield();
            }
        }
        catch (DivideByZeroException ex)
        {
            Console.WriteLine("Exception thrown in " + nameof(Divide1));
            throw;
        }
    }
    public static async Task Divide2(int v1, int v2)
    {
        try
        {
            Console.WriteLine(nameof(Divide2) + ".1");
            await Task.CompletedTask;
            Console.WriteLine(nameof(Divide2) + ".2");
            if (v1 / v2 > 1)
            {
                await Task.Yield();
            }
        }
        catch (DivideByZeroException ex)
        {
            Console.WriteLine("Exception thrown in " + nameof(Divide2));
            throw;
        }
    }
}

/* Output
Before calling Divide1
Divide1.1
After calling Divide1
Divide1.2
Exception thrown in Divide1
Exception thrown in Main
Before calling Divide2
Divide2.1
Divide2.2
Exception thrown in Divide2
After calling Divide2
Exception thrown in Main
*/

这证明如果它与您发布的完全一样,您本可以抛出。

我在这里错过了什么吗?

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM