Изменение на лету значения длительного процесса в целях проверки в модульном тесте - PullRequest
1 голос
/ 21 марта 2020

У меня есть следующий метод:

public async Task ScrapeObjects(int page)
{
    try
    {
        while (!isObjectSearchCompleted)
        {
            UriBuilder builder = new UriBuilder(_apiSettings.Value.FundaUrl)
            {
                Query = $"test"
            };
            var result = await _apiCaller.GetResponseAsync<ResponseModel>(builder.Uri).ConfigureAwait(false);
            Thread.Sleep(TimeSpan.FromSeconds(1));

            if (result != null)
            {
                foreach (var obj in result.Objects)
                {
                    UpdateDictionary(propertiesAmount, obj.name);
                }
            }
            if (!fundaResult.Objects.Any())
            {
                isObjectSearchCompleted = true;
            }
            else
            {
                page++;
            }
        }
    }
    catch (HttpRequestException ex)
    {
        if (ex.Message == "Request limit exceeded.")
        {
            Thread.Sleep(TimeSpan.FromSeconds(60));
            ScrapeObjects(page);
        }
        Log.Fatal(ex, ex.Message);
    }
}

Я пытаюсь протестировать его. Однако это длительный процесс. У меня есть контроль над _apiCaller , так как я над ним издеваюсь. Я пытаюсь протестировать следующие 2 сценария ios:

1) _apiCaller возвращает правильный результат в первый раз. Мой словарь обновляется через UpdateDictionary . Вместо этого второй вызов не возвращает результата, и, следовательно, весь метод достигает своего конца. Цель моего теста - убедиться, что мой словарь обновлен.

или

2) _apiCaller возвращает правильный результат в первый раз. Мой словарь обновляется через UpdateDictionary . Второй вызов вместо этого выдает исключение, и мой метод завершается. Цель моего теста - убедиться, что мой словарь обновлен.

В обоих случаях мне нужно изменить поведение моего метода (моего поддельного _apiCaller ) на лету или в по крайней мере после первого раза это называется. Как мне этого добиться? Заранее спасибо!

1 Ответ

1 голос
/ 22 марта 2020

Используйте SetupSequence для настройки поведения макета при вызове.

1) _apiCaller возвращает правильный результат в первый раз. Мой словарь обновляется через UpdateDictionary. Вместо этого второй вызов не возвращает результата, и, следовательно, весь метод достигает своего конца. Цель моего теста - убедиться, что мой словарь обновлен.

apiMock.SetupSequence(_ => _.GetResponseAsync<ResponseModel>(It.IsAny<Uri>()))
    .Returns(Task.FromResult(correctResponseModel)) // returns the correct result the first time.
    .Returns(Task.FromResult((ResponseModel)null)); // The second call instead returns no result

2) _apiCaller возвращает правильный результат в первый раз. Мой словарь обновляется через UpdateDictionary. Второй вызов вместо этого выдает исключение, и мой метод завершается. Цель моего теста - убедиться, что мой словарь обновлен.

apiMock.SetupSequence(_ => _.GetResponseAsync<ResponseModel>(It.IsAny<Uri>()))
    .Returns(Task.FromResult(correctResponseModel)) // returns the correct result the first time.
    .Throws(new HttpRequestException("Request limit exceeded.")); //second call throws an exception

При этом не смешивайте async-await с Thread.Sleep Используйте Task.Delay

await Task.Delay(TimeSpan.FromSeconds(1));

//...

Вы открываете себе нежелательное поведение в catch, так как повторный вызов не ожидается.

catch (HttpRequestException ex)
{
    if (ex.Message == "Request limit exceeded.")
    {
        Thread.Sleep(TimeSpan.FromSeconds(60));
        ScrapeObjects(page); //<-- not awaited.
    }
    Log.Fatal(ex, ex.Message);
}

Я бы предложил изучить Retry Pattern, чтобы лучше справиться с этим сценарием в вашем дизайне

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...