我确信一旦测试完成,它会指出一些需要改变的东西才能让所有东西都能用到UI,但基本上我有这个:
frmMain:
Dim totalFinished as Integer = 0
reporter as Func(Of Object) = Function()
totalFinished += 1
return Nothing
End Function
classWithAsync.setReporter(reporter)
classWithAsync.BeginCalculation() ' ignore that this is a private method call
' there is another method I'm leaving out (the public one) which just does
' some set up stuff and then calls BeginCalculation
' Note: this notice isn't actually in my code
ClassWithAsync:
Private Async Sub BeginCalculation()
' some logic here
If synchronous Then
CalculatorCalculate(calculator)
Else
Await calculatorAsyncCalculate(calculator)
End If
End Sub
Private Async Function calculatorAsyncCalculate(ByVal calculator as Calculatable) as Hashtable
Dim result as Hashtable
result = Await Tasks.Task.Run(Function() as Hashtable
return calculator.Calculate()
EndFunction)
reporter.Invoke()
return result
End Function
Private Function CalculatorCalculate(ByVal calculator as Calculatable) as Hashtable
Dim result as Hashtable
result = calculator.Calculate()
reporter.Invoke()
return result
End Function
这里的意图是让记者两次调用。我在同步版本中工作..但是线程测试就像线程甚至没有运行一样(这可能是因为执行正在继续,并且断言在线程完成之前进行评估?)
以下是我的测试:
同步:(通过)
<TestMethod> Public Sub UpdatesForEachSynchronousProduct()
Dim data As Hashtable = TestData.GenerateGroupData("LTD,WDL")
CreateMockCalculators(data, privateTarget)
privateTarget.SetFieldOrProperty("reporter", reporter)
privateTarget.SetFieldOrProperty("synchronous", True)
privateTarget.Invoke("BeginCalculation")
Assert.AreEqual(2, totalCalculated)
End Sub
异步:(不通过)
<TestMethod> Public Sub UpdatesForEachAsyncProduct()
Dim data As Hashtable = TestData.GenerateGroupData("LTD,WDL")
CreateMockCalculators(data, privateTarget)
privateTarget.SetFieldOrProperty("reporter", reporter)
privateTarget.SetFieldOrProperty("synchronous", False)
privateTarget.Invoke("BeginCalculation")
Assert.AreEqual(2, totalCalculated)
End Sub
这个错误是它预期2,但totalCalculated是0。
那么,有没有办法让Assert等到线程完成?
答案 0 :(得分:0)
想出来。
好吧,我认为某事了
虽然,这种黑客的做法。在这一刻,我不确定它是否仍然是异步的,也许有比我更多异步经验的人可以对此发表评论。我很确定它仍然是Async。当我进一步实施整个项目时,我会更了解。
必须更改BeginCalculation()
方法:
Private Sub BeginCalculation()
For Each calculator As Calculatable In calculatables
If synchronous Then
CalculatorCalculate(calculator)
Else
' Call this without Await so that the for each loop
' may continue spawning calculation tasks
' Calling Await halts the execution of this method
CalculatorAsyncCalculate(calculator)
End If
Next
End Sub
之前,我在Await
上使用CalculatorAsyncCalculate
,这会停止执行循环,直到线程结束 - 这是不受欢迎的。 Visual Studio会抱怨此情况(作为警告)并建议我添加Await
并将Async
添加到方法标头中。但是......我们可以忽略视觉工作室。
这是我的异步方法:
Private Async Function CalculatorAsyncCalculate(ByVal calculator As Calculatable) As Tasks.Task(Of Hashtable)
Dim result As Hashtable
Dim task As New Tasks.Task(Function() As Hashtable
calculator.Calculate()
' Update the reporter
If Not reporter Is Nothing Then
reporter.Invoke()
End If
Return calculator.GetCalculatedData()
End Function)
calculationTasks.Add(task)
result = Await Tasks.Task.Run(Function()
' Begin calculations
task.Start()
' Wait until the calculations are done
' before returning the results
task.Wait()
Return calculator.GetCalculatedData()
End Function)
Return result
End Function
我不需要只是异步地运行我需要的东西,而是将代码放入Task对象中,这样我就可以将它添加到跟踪任务的ArrayList中。该数组的目的是让我可以在测试中传递给Threading.Tasks.Task.WaitAll(...)
。有点令人费解,但我想它可以更灵活地决定将来如何处理各项任务。
然后我的测试:
<TestMethod> Public Sub UpdatesForEachAsyncProduct()
Dim data As Hashtable = TestData.GenerateGroupData("LTD,WDL")
CreateMockCalculators(data, privateTarget)
privateTarget.SetFieldOrProperty("reporter", reporter)
privateTarget.SetFieldOrProperty("synchronous", False)
privateTarget.Invoke("BeginCalculation")
Dim calcTasks As ArrayList = privateTarget.GetFieldOrProperty("calculationTasks")
Dim cTasks(calcTasks.Count - 1) As System.Threading.Tasks.Task
Dim array() = calcTasks.ToArray()
array.CopyTo(cTasks, 0)
Assert.AreEqual(2, cTasks.Count)
System.Threading.Tasks.Task.WaitAll(cTasks)
Assert.AreEqual(2, totalCalculated)
End Sub
privateTarget
是PrivateObject(classWithAsync)
所以我可以获得私有属性和方法。
在调用wait all之前,我只是确保我有正确数量的任务,以确保BeginCalculation
迭代了两个对象,并产生了两个线程。
WaitAll(cTasks)
电话在这里是神奇的。没有我失败说Assert预期2但收到1。
答案 1 :(得分:-1)
良好的单元测试的一个基本特征是它应该测试单元;也就是说它应该测试一个单独的,独立的独立功能。多个线程本质上并不是彼此独立的,并且可以以不易重现的方式进行交互以进行测试。
基于此,我认为你应该测试线程之外的实际计算(calculator.Calculate()
)。
尝试在线程存在的情况下测试计算是试图同时测试太多东西,恕我直言。