帮助从c#的单元测试中同步

本文关键字:同步 单元测试 帮助 | 更新日期: 2023-09-27 17:50:07

我正在测试一个包装BackgroundWorker的类,以便在我的应用程序中执行远离UI线程的操作。

如果超过Timeout,下面的测试将失败,如果在此之前progressevencount达到预期的事件数,则通过。

我的问题是关于同步的。asyncExecutor。progress从BackgroundWorker正在使用的线程池线程中触发,测试线程在while循环中读取它。

我是否正确使用了lock ?

    [Test]
    [Timeout(1250)]
    public void Execute()
    {
        var locker = new object();
        const int numberOfEvents = 10;
        const int frequencyOfEvents = 100;
        var start = DateTime.Now;
        int progressEventCount = 0;
        IGradualOperation tester = new TestGradualOperation(numberOfEvents, frequencyOfEvents);
        var asyncExecutor = new AsynchronousOperationExecutor();
        asyncExecutor.Progressed += (s, e) => { lock (locker) progressEventCount++; };
        asyncExecutor.Execute(tester);
        while (true)
        {
            int count;
            lock (locker)
            {
                count = progressEventCount;
            }
            if (count < numberOfEvents) continue;
            Assert.Pass("Succeeded after {0} milliseconds", (DateTime.Now - start).TotalMilliseconds);
        }
    }

//  Implementation
public class AsynchronousOperationExecutor
{
    public void Execute(IGradualOperation gradualOperation)
    {
        var backgroundWorker = new BackgroundWorker {WorkerReportsProgress = true};
        backgroundWorker.DoWork += BackgroundWorkerDoWork;
        backgroundWorker.ProgressChanged += BackgroundWorkerProgressChanged;
        backgroundWorker.RunWorkerAsync(gradualOperation);
    }
    private void BackgroundWorkerProgressChanged(object sender, ProgressChangedEventArgs e)
    {
        var myArgs = e.UserState as ProgressEventArgs;
        OnProgressed(myArgs);
    }
    static void BackgroundWorkerDoWork(object sender, DoWorkEventArgs e)
    {
        var workerThis = sender as BackgroundWorker;
        var operation = e.Argument as IGradualOperation;
        if (workerThis == null || operation == null) return;
        operation.Progressed += (s, e1) => workerThis.ReportProgress((int)e1.Percentage, e1);
        operation.Run();
    }
    private void OnProgressed(ProgressEventArgs e)
    {
        if (Progressed != null)
            Progressed(this, e);
    }
    public event EventHandler<ProgressEventArgs> Progressed;
}

//   Test Helper Class
public class TestGradualOperation : IGradualOperation
{
    private readonly int _numberOfEvents;
    private readonly int _frequencyMilliseconds;
    public TestGradualOperation(int numberOfEvents, int frequencyMilliseconds)
    {
        _numberOfEvents = numberOfEvents;
        _frequencyMilliseconds = frequencyMilliseconds;
    }
    public void Run()
    {
        for (int i = 0; i < _numberOfEvents; i++)
        {
            Thread.Sleep(_frequencyMilliseconds);
            OnProgressed(new ProgressEventArgs(i, _numberOfEvents));
        }
    }
    private void OnProgressed(ProgressEventArgs e)
    {
        if (Progressed != null)
            Progressed(this, e);            
    }
    public event EventHandler<ProgressEventArgs> Progressed;
}

帮助从c#的单元测试中同步

我认为这个修订是一个改进,阻塞测试线程和AutoResetEvent信号。虽然没有为测试可读性赢得任何加分。

    [Test]
    [Timeout(1250)]
    public void Execute()
    {
        var locker = new object();
        EventWaitHandle waitHandle = new AutoResetEvent(false);// <--
        const int numberOfEvents = 10;
        const int frequencyOfEvents = 100;
        var start = DateTime.Now;
        int progressEventCount = 0;
        IGradualOperation tester = new TestGradualOperation(numberOfEvents, frequencyOfEvents);
        var asyncExecutor = new AsynchronousOperationExecutor();
        asyncExecutor.Progressed += (s, e) =>
        {
            lock (locker)
            {
                progressEventCount++;
                waitHandle.Set();// <--
            }
        };
        asyncExecutor.Execute(tester);
        while (true)
        {
            waitHandle.WaitOne();// <--
            if (progressEventCount < numberOfEvents) continue;
            Assert.Pass("Succeeded after {0} milliseconds", (DateTime.Now - start).TotalMilliseconds);
        }
    }