帮助从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;
}
我认为这个修订是一个改进,阻塞测试线程和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);
}
}