Autofixture: Создайте альтернативный GuardClauseAssertion, который поддерживает методы, помеченные как `async`.

Созданный на 1 мар. 2019  ·  12Комментарии  ·  Источник: AutoFixture/AutoFixture

Как обсуждалось в # 268, класс GuardClauseAssertion не ожидает завершения задач, что делает его неспособным проверять быстрые методы без

Это вполне понятно, ведь отказоустойчивый режим - действительно лучший вариант. Тем не менее, кажется невозможным реализовать быстрое отказоустойчивое поведение при работе с методами, отмеченными ключевым словом async .

enhancement

Самый полезный комментарий

@ploeh В принципе, _any_ async метод не работает без сбоев. Рассмотрим следующий пример:

`` С #
общедоступная асинхронная задачаGuardedOpenGenericMethodReturningTaskResult(аргумент объекта)
{
if (arg == null) выбросить новое исключение ArgumentNullException (nameof (arg));

await Task.Yield();

return default;

}
`` ''

Этот метод не срабатывает, если вы вызываете его, будет null . Вместо этого возвращается неудачный Task . Следовательно, GuardClauseAssertion в его текущей форме не работает и жалуется на отсутствие защитного предложения.

В реальном приложении почти весь код - async , поэтому каждый вызов - awaited и немедленно выдается исключение. Так что совершенно нормально, что принцип «быстрого отказа» нарушается в том случае, если вы должны await Task, чтобы увидеть исключение.

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

Все 12 Комментарий

кажется невозможным реализовать поведение _fail fast_ при работе с методами, отмеченными ключевым словом async .

Как так? Вы можете привести пример?

@ploeh В принципе, _any_ async метод не работает без сбоев. Рассмотрим следующий пример:

`` С #
общедоступная асинхронная задачаGuardedOpenGenericMethodReturningTaskResult(аргумент объекта)
{
if (arg == null) выбросить новое исключение ArgumentNullException (nameof (arg));

await Task.Yield();

return default;

}
`` ''

Этот метод не срабатывает, если вы вызываете его, будет null . Вместо этого возвращается неудачный Task . Следовательно, GuardClauseAssertion в его текущей форме не работает и жалуется на отсутствие защитного предложения.

В реальном приложении почти весь код - async , поэтому каждый вызов - awaited и немедленно выдается исключение. Так что совершенно нормально, что принцип «быстрого отказа» нарушается в том случае, если вы должны await Task, чтобы увидеть исключение.

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

В реальном приложении почти весь код - async , поэтому каждый вызов - awaited и сразу же выдается исключение.

Это справедливый момент; Я принимаю этот аргумент.

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

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

Да, это справедливо

Теперь позвольте мне подумать, как я могу переделать GuardClauseAssertion чтобы не было логического флага - если честно, мне это тоже не нравится. Увидимся позже в PR.

Теперь позвольте мне подумать, как я могу перепроектировать GuardClauseAssertion чтобы не было логического флага

Я бы подумал, что, как предположил @moodmosaic , новый класс мог бы быть лучшим дизайном. Я не особо разбирался в проблеме, поэтому оставляю за собой право ошибаться 😄

Вот решение, которое я использовал.

  1. Удалите ключевое слово async сигнатуры метода.
  2. Создайте вложенный метод с ключевым словом async
  3. Поместите защитные предложения во внешнюю часть метода
  4. Вызвать вложенный метод и вернуть результаты

Пример:

public Task<int> GetNumberAsync(MyObject obj)
{
    // Fail-fast behavior
    if (request is null)
        throw new ArgumentNullException(nameof(obj));

    async Task<int> work()
    {
        var items = await obj.GetItemsAsync(); // whatever you need to call
        return items.Count();
    }

    return work();
}

Для меня это было хорошим решением. Спасибо за вашу помощь.

@mniak Интересно есть пример того , что конкретный @zvirja предложил здесь .

Лично мне это не очень нравится, потому что мы загрязняем этот метод «уловками» в пользу среды тестирования, что для меня очень плохо пахнет, и я бы не хотел, чтобы моя команда использовала этот шаблон.

Оставьте его открытым, чтобы реализовать поддержку естественным образом. Когда-нибудь. В ближайшем будущем. Или всего один день.

Привет. Мы наткнулись именно на эту проблему и были удивлены, что пока не существует хорошего решения.
Есть ли причины не реализовывать для этого новый класс?
Я не знаю внутренних деталей AutoFixture, но если бы у нас был MethodInfo, доступный в классе GuardClauseAssertion для Method-to-Test, мы могли бы взглянуть на его CustomAttributes и определить, является ли он методом Async или нет (https: / /stackoverflow.com/a/20350646). Так что, возможно, переключатель (bool vs. new class) даже не нужен.

@zvirja @aivascu, можем ли мы это пересмотреть? Я действительно не понимаю, почему в 2021 году асинхронные методы нельзя протестировать должным образом.

@Kralizek, если я правильно прочитал ситуацию, запрос не был отклонен, и есть даже PR, который это исправляет.
Я бегло просмотрел PR и должен сказать, что согласен с полученными отзывами.
Так что остается только либо реализовать обратную связь, либо подать новый PR с реализованной обратной связью.

Связанный PR в мобильном приложении не увидел 😅

Была ли эта страница полезной?
0 / 5 - 0 рейтинги