0

Я уверен, что после того, как тест написан, это будет указать на некоторые вещи, которые необходимо будет изменить для того, чтобы получить все работает с пользовательским интерфейсом, но в основном у меня есть это:Как я могу протестировать мое приложение vb.net с резьбой?

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 

намерение здесь, чтобы репортер вызывать дважды. Что я работаю в синхронной версии .. но тест с резьбой действует так, как будто поток даже не запускался (возможно, из-за того, что выполнение продолжается, а утверждение оценивается до завершения потоков)

Вот мои тесты:

Synchronous: (Передает)

<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 

асинхронный: (не Pass)

<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 

погрешность для этого является то, что EXP ected 2, но totalCalculated был 0.

Итак, есть ли способ сделать Assert ждать, пока потоки не будут выполнены?

+0

Возможно, вам это поможет: http://stackoverflow.com/q/12159/951890 –

ответ

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

Одной из основных особенностей хорошего модульного испытания является то, что он должен испытать блок ; то есть он должен протестировать единую автономную независимую функцию. Несколько потоков по самой своей природе не являются независимыми друг от друга и могут взаимодействовать способами, которые нелегко воспроизводиться для тестирования.

Основываясь на этом, я бы сказал, что вы должны проверить фактический расчет (calculator.Calculate()) за пределами резьбы.

Попытка проверить расчет при наличии резьбы пытается одновременно проверить слишком много вещей, ИМХО.

+0

У меня есть тест для метода 'Calculate()'. Я просто хочу проверить, что я правильно настроил потоки, и что любые изменения в реализации потоковой обработки не влияют на конечный результат. Тесты должны быть способны охватить все аспекты приложения. Возможно, более подходящим термином будет интеграционный тест. – NullVoxPopuli

Смежные вопросы