Как я могу выполнить модульное тестирование асинхронного метода в F #? - PullRequest
0 голосов
/ 30 января 2019

У меня есть метод, который возвращает задачу, которую я пытаюсь синхронно протестировать в F #.Вот метод, который является реализацией интерфейса C #:

member this.RunAsync(): System.Threading.Tasks.Task =             
    async{
        this._settings.LogSettings |> Seq.iter(fun settings -> this.clearLogs(settings)) |> ignore
        return ()
        } |> Async.StartAsTask :> _

Вот моя логика теста

Async.AwaitTask(logFileManager.RunAsync())|> Async.Ignore
// and I've tried
async {
  logFileManager.RunAsync() 
  Assert.Pass()
} |> Async.RunSynchronously

Тест выполняется, и с 5 пунктами ожидаемое количество вызовов должнобыть 5, но тест завершается неудачно со случайным числом вызовов от 1 до 2.

Тот же тест в C # для другой реализации просто:

[Test]
public async Task Should_do_something_in_an_asynchronous_method()
{
    var unitUnderTest = GetService();
    await unitUnderTest.RunAsync();
}

Как обеспечить выполнение задачизавершено для модульных тестов?

Как написать эквивалентный метод теста с async?

1 Ответ

0 голосов
/ 30 января 2019

Взгляните на слово await в вашем коде C #.Как вы думаете, что это делает?Что если вы уронили его?Будет ли тест все еще работать?

Ответы таковы: «Это делает асинхронный вызов частью окружающего асинхронного вычисления» и «Нет, не будет»

Не будет, потому чтовызов RunAsync больше не будет частью окружающих вычислений, и окружающие вычисления не будут знать, что ему нужно «ждать», чтобы завершить его.

И это именно то, что вы 'Вы делаете в своем коде F #: вы просто вызываете функцию и забываете о ней, не делая ее частью окружающего рабочего процесса.Функция отключается и начинает работать сама по себе, и ваш async рабочий процесс отключается в другом направлении.

В F # способ сделать вложенные вызовы частью окружающего потока с помощью let!или do! ключевые слова, которые в некоторой степени аналогичны await в C #.Например:

let f = async { ... }
let g = async {
    let! x = f
    printfn "f returned: %A" x
}

Но в вашем случае это не сработает сразу, потому что RunAsync возвращает C # Task, а не F # Async.Таким образом, вам также необходимо преобразовать из первого в последнее.Чтобы выполнить преобразование, используйте функцию Async.AwaitTask:

async {
  do! logFileManager.RunAsync() |> Async.AwaitTask
  Assert.Pass()
} |> Async.RunSynchronously
...