Я работаю над проектом ASP.NET Web Api, чтобы изучить структуру и ее тестирование, и мне было интересно, можете ли вы проверить, что асинхронные методы на самом деле работают асинхронно (или работают ли они синхронно, например, из-за каких-либо ошибок).
public class RepositoryBase<Tentity, Tcontext> : IRepositoryBase<Tentity> where Tentity : class where Tcontext : DbContext
{
protected Tcontext _RepositoryContext;
protected DbSet<Tentity> dbSet;
public RepositoryBase(Tcontext context)
{
this._RepositoryContext = context;
dbSet = _RepositoryContext.Set<Tentity>();
}
public async Task Create(Tentity entity)
{
await dbSet.AddAsync(entity);
}
}
Можете ли вы проверить, действительно ли метод Create работает асинхронно? Логично ли проверять, работает ли метод асинхронно? Или это тривиальная проблема, потому что тот факт, что он возвращает Task, является доказательством того, что он работает асинхронно.
Во время модульного тестирования в моей тестовой функции я только попробовал await repository.Create(testUser);
, а затем позже подтвердил, что пользователь внутри базы данных и тот, кого я ввел, идентичны во всех аспектах. Но это всего лишь проверка конечной функциональности функции Create, а не того, успешно ли она работает асинхронно или нет.
Моя цель — не протестировать или подвергнуть сомнению саму эту конкретную структуру, а задаться вопросом, можно ли протестировать какую-либо общую асинхронную функцию на предмет ее асинхронной природы. Приведенный выше пример кода — это всего лишь контекст, при котором этот вопрос появился у меня в голове.
Звучит так, как будто вы не доверяете фреймворку, выполняющему асинхронные действия, когда вы сообщаете фреймворку/среде выполнения, написав соответствующий код, что он должен это делать? Вы намерены тестировать фреймворк/среду выполнения?
Вы бы проверили внутреннюю часть своей функции. С точки зрения клиента совершенно не имеет значения, действительно ли функция вообще выполняет какой-либо асинхронный код. Вас должно волновать только то, что он возвращает, а это задача. API не дает никаких других обещаний, поэтому вам не следует беспокоиться о других.
@Ральф return Task.FromResult(VerySynchronous());
@GSerg Затем вы сказали среде выполнения через код, что она не должна быть асинхронной. Для этого нужен тест?
@Ralf Сама предпосылка вопроса заключается в том, что вы являетесь потребителем функции, которая может делать return Task.FromResult(VerySynchronous());
, но вы этого не знаете. Откуда бы вы это узнали, и если бы был способ узнать, что бы вы искали? Ничто из этого не имеет ничего общего с тестированием корректности реализации асинхронности в фреймворке.
если вы не доверяете фреймворку, в случае framework things
вам следует подумать о написании своего собственного. Это вопрос навыков программиста, если его «асинхронный код» работает как синхронный, и почти невозможно проверить это на 100%.
@GSerg Я думаю, дело в том, что клиент функции, которая возвращает Task
, не должен ожидать, что она будет выполняться асинхронно (всегда). И именно поэтому тестирование, если оно есть, не имеет смысла.
@WhiteH С точки зрения потребителя все, о чем вас должно волновать, это то, чтобы функция возвращала ожидаемое значение (что Task
является наиболее распространенным примером). Кроме того, вы быстро обнаружите, что вам действительно нужно сначала определить «асинхронную работу», чтобы иметь возможность ее протестировать. Вы, например, имеете в виду, что вызываемая функция в какой-то момент переходит в фазу без потока? Я понятия не имею, как вы будете это проверять.
@GSerg. Он говорит о юниттесте. Итак, предположительно, набор баз данных высмеивается и, по-видимому, выполняет Task.FromResult. Таким образом, в его тесте он будет синхронизирован, тогда как в производстве он может быть асинхронным. Я понимаю вашу точку зрения, но ее невозможно проверить в классическом смысле модульного тестирования.
«Моя цель состоит в том, чтобы [...] задаться вопросом, следует ли/может ли какая-либо общая асинхронная функция быть проверена на ее асинхронную природу». -- Должен или мог бы? Это два совершенно разных вопроса. Первоначальный вопрос (редакция 1) был о возможности. Если вы хотите узнать о необходимости, я бы предложил задать новый вопрос. К вашему сведению, вопросы по StackOverflow, как ожидается, будут одномерными. Вопросы, в которых задается более чем один вопрос, обычно закрываются по причине «слишком обширно, недостаточно сфокусировано». Однако вопрос о необходимости можно закрыть, поскольку он основан на мнении.
Можете ли вы проверить, действительно ли метод
Create
работает асинхронно?
Да, но не со 100% уверенностью. Вы можете проверить, что метод возвращает Task
, который еще не завершен. Вместо:
await repository.Create(testUser);
...сделай это:
Task task = repository.Create(testUser);
Debug.Assert(!task.IsCompleted);
await task;
task.IsCompleted
ложно, это означает, что в будущем задача будет выполнена асинхронно.task.IsCompleted
истинно, это означает, что либо оно завершилось синхронно, либо оно завершилось асинхронно настолько быстро, что у вас не было возможности наблюдать за этим (крайне маловероятный сценарий).ИМХО этот вопрос не имеет особого смысла. Представьте себе такую функцию синхронизации:
int DoSomething(int i) { ... }
С точки зрения потребителя все, что вы знаете (и все, что вам следует проверять), — это то, что ожидает функция и что она возвращает в этом случае. Вы никогда не придете к предположению проверить, действительно ли функция что-нибудь делает с параметром. Вместо этого вы просто проверяете возвращаемое значение.
Ваш асинхронный код ничем не отличается: он возвращает Task
, который делает вид, что внутри него выполняется какой-то асинхронный код.
Task DoSomething() { ... }
При вызове этой функции мы заботимся только о ее внешнем виде, а не о ее фактической реализации. У нас нет возможности проверить, что он делает внутри. Мы можем просто предположить, что там есть что-то асинхронное. Даже ключевое слово async
нам ничего не говорит. Если бы функция была определена в интерфейсе, async
вообще не существовало бы, поэтому на это мы тоже не могли бы полагаться.
Так что, в конце концов, нет смысла проверять, действительно ли функция вызывает какой-либо асинхронный код или она просто делает вид, что это делает; то же, что и в первом примере, если он действительно использует параметр.
«который притворяется, что внутри него работает какой-то асинхронный код» - на самом деле только притворяется, что имеет потенциал для запуска асинхронного кода, верно?
@fildor ээээхм, ну, когда это asnyc
функция, я бы сказал, что функция определенно потенциально может делать что-то асинхронно. Нет await
без async
. Однако в функции без async
да, я понимаю вашу точку зрения.
Точно. Если мы подумаем об интерфейсе, async
не будет его частью. Просто возвращаемый тип Task
. Любая реализация может иметь это или нет. -- Просто мысль, без каких-либо конкретных замечаний...
Нет, нет и нет, в порядке вопросов.