简体   繁体   English

在同步测试中使用 xUnit.net 将测试标记为异步

[英]Marking tests async with xUnit.net on synchronous tests

Is there any benefit to setting the signature of tests such as async Task MyTest() with synchronous tests?使用同步测试设置测试签名(例如async Task MyTest()有什么好处? Does xUnit.net run faster if you do?如果这样做,xUnit.net 会运行得更快吗? Or are they unnecessary?还是它们是不必要的?

Marking synchronous tests as async will make your tests run slower将同步测试标记为异步将使您的测试运行更慢

xUnit asynchronous tests should only be used to test asynchronous methods. xUnit 异步测试应该只用于测试异步方法。 Arbitrarily marking synchronous test methods as asynchronous will actually make execution significantly slower .随意将同步测试方法标记为异步实际上会使执行速度明显变慢

Why would an async method be slower?为什么async方法会更慢?

This happens because .NET does quite a bit more work to invoke an asynchronous task than it does to invoke a standard method.发生这种情况是因为 .NET 调用异步任务比调用标准方法做的工作要多得多。 Marking any synchronous .NET method as async will make the execution of that method slower and xUnit test methods are not an exception to this rule.将任何同步 .NET 方法标记为async将使该方法的执行速度变慢,xUnit 测试方法也不例外。

To illustrate this point, I put together a simple dotnetfiddle with benchmarks comparing asynchronous and synchronous execution of a SHA1 hash computation.为了说明这一点,我将一个简单的 dotnetfiddle 与比较 SHA1 hash 计算的异步和同步执行的基准放在一起。 The significance of the execution penalty will vary depending on the duration of the core computation.执行惩罚的重要性将根据核心计算的持续时间而有所不同。 In this particular example, running the synchronous version was consistently about 10 times faster than when the operation was invoked asynchronously .在这个特定示例中,运行同步版本始终比异步调用操作快 10 倍左右 I'll include this code at the end of the answer, because I want to make a few other points first.我将在答案末尾包含此代码,因为我想先说明其他几点。

How xUnit runs your test xUnit 如何运行您的测试

You can see how xUnit invokes test methods by examining the code in the TestInvoker and its subclass XunitTestInvoker .您可以通过检查TestInvoker及其子类XunitTestInvoker中的代码来了解 xUnit 如何调用测试方法。 Basically, every test method is executed by an async method in the runner.基本上,每个测试方法都由运行器中的异步方法执行。 xUnit uses reflection to invoke the test method. xUnit 使用反射来调用测试方法。 If the test method is async, then the xUnit runner method will wait for the test method task to finish.如果测试方法是异步的,那么 xUnit 运行器方法将等待测试方法任务完成。

Speculation: Why you might be considering making your tests async and what to do instead推测:为什么你可能会考虑让你的测试异步以及该怎么做

In general, performing asynchronous operations can improve performance because the work of the asynchronous operation can continue while the main thread does some other work.一般来说,执行异步操作可以提高性能,因为异步操作的工作可以在主线程做一些其他工作的同时继续进行。 My guess is that your hope in asking this question is that xUnit would continue to do other work while the methods you marked async are running.我的猜测是,您提出这个问题的希望是,当您标记为async的方法正在运行时,xUnit 将继续做其他工作。 While that's not what would happen, xUnit does provide a way to execute multiple tests concurrently.虽然这不会发生,但 xUnit 确实提供了一种同时执行多个测试的方法。 The appropriate technique to achieve this is to configure xUnit for running tests in parallel .实现此目的的适当技术是配置 xUnit以并行运行测试 Parallelism in xUnit test execution is orthogonal to the synchronization of your test methods, so this can be leveraged to more quickly execute both synchronous and asynchronous tests. xUnit 测试执行中的并行性与测试方法的同步是正交的,因此可以利用它来更快地执行同步和异步测试。

benchmarks of synchronous vs asynchronous execution of synchronous operations同步操作的同步与异步执行的基准

using System;
using System.Diagnostics;
using System.Security.Cryptography;
using System.Threading.Tasks;

public class Program
{
    public static void Main() {

        TimeSpan
            averageSyncTime = TimeSpan.MinValue,
            averageAsyncTime = TimeSpan.MinValue;

        // init stopwatch
        var t = Stopwatch.StartNew();
        t.Stop();
        t.Reset();

        using(var algorithm = SHA1.Create()){
            var i = -1;
            var iMax= 10000;

            Action SyncOperationToTest = () => {
                var hash = algorithm.ComputeHash(BitConverter.GetBytes(i));
            };

            // start testing synchronous execution of synchronous operation
            t.Start();
            for(i = 1; i <= iMax; i++){
                SyncOperationToTest();
            }

            t.Stop();
            averageSyncTime = TimeSpan.FromTicks(t.ElapsedTicks/iMax);
            // stop testing synchronous execution of synchronous operation 

            t.Reset();

            // start testing asynchronous execution of synchronous operation
            t.Start();
            for(i = 1; i <= iMax; i++){
                Task.Run(SyncOperationToTest).Wait();
            }       
            t.Stop();
            averageAsyncTime = TimeSpan.FromTicks(t.ElapsedTicks/iMax);
            // stop testing asynchronous execution of synchronous operation 

            var howManyTimesSlowerIsAsync = Math.Round(averageAsyncTime.TotalMilliseconds/averageSyncTime.TotalMilliseconds, 1);

            Console.WriteLine("When called synchronously, the average operation time was {0}ms.", averageSyncTime.TotalMilliseconds);
            Console.WriteLine("When called in an artificial asynchronous wrapper, the average operation time was {0}ms.", averageAsyncTime.TotalMilliseconds);
            Console.WriteLine("Arbitrarily calling the example synchronous operation in an asynchronous wrapper was about {0} times slower than simply calling it synchronously.", howManyTimesSlowerIsAsync);
        }
    }
}

Unless you are testing asynchronous operations it is unnecessary to use the method signatures you mentioned.除非您正在测试异步操作,否则没有必要使用您提到的方法签名。 And Xunit will not run faster whether you have used it or not.而且Xunit不管你有没有用过都不会跑得更快。 The efficiency of your test operation depends on your logic.测试操作的效率取决于您的逻辑。

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

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