Size: a a a

2020 January 27

RB

Roman Bolkhovitin in rannts
а можно поинтересоваться, почему юнит тест не на саму эту корутину, обмазанную фикстурами, а на внешнюю функцию? ну во всяком случае я так понял
источник

БС

Байт Словович in rannts
Ну потому что, теория и практика не одно и тоже.
Лишний тест, это лишнее время запуска тестов. Уже сейчас тесты больше 10 минут на тимсити идут.
Во вторых для запуска этой корутинки, нужно много подготовки и приседаний сделать, которые делаются в the функции. То есть мне надо в тесте достаточно много скопипастить.
Но если бы я её мог легко вытащить, то я бы так и сделал..
источник

SA

Sergey Arkhipov in rannts
Байт Словович
Хм, столкнулся с проблемой.

Есть код, который в нормальном случае должен работать асинхронно. (В моем случае это обновление нескольких полей, которые берутся из thirdparty внешней системы, и таймауты там огромные могут быть, но эти поля не влияют на основной функционал, поэтому я могу позволить их обновить позже. ) Пишу вот так:
asyncio.ensure_future(xxx())

Но вот в этой xxx могут быть ошибки, и мне желательно в unittestах их все поймать, то есть чтобы тест сразу упал  надо делать синхронный вызов. Получается код аля:
coro = xxx()
if test:
   await coro
else:
  asyncio.ensure_fututre(coro)


А это как то не красиво. Понятно что можно написать обертку аля:
def ensure_future(coro):
   if test:
       await coro
   else:
      asyncio.ensure_future(coro_

ensure_future(xxx())

Это красивее, но получается что в юниттестах тестируется только один бранч в этой функции. То есть асинхронный вызов не тестируется.
Кто нить с подобным сталкивался и красиво решал?
cat main.py
import asyncio


async def coro():
   raise ValueError()


async def main():
   try:
       await coro()
   except Exception as exc:
       print(f"Raised {exc}")
   else:
       print("Not raised")


asyncio.run(main())
- пишет Raised. А зачем ensure_future-то использовать?
источник

SA

Sergey Arkhipov in rannts
Или в чем проблема? Как синхронно корутину позвать? run_until_complete
источник

SA

Sergey Arkhipov in rannts
import asyncio


async def coro():
   raise ValueError()


def main():
   try:
       asyncio.get_event_loop().run_until_complete(coro())
   except Exception as exc:
       print(f"Raised {exc}")
   else:
       print("Not raised")


main()
- я чувствую, будто не понимаю твоей проблемы 🙁
источник

SA

Sergey Arkhipov in rannts
Artem Malyshev
DI, DI, DI, DI, DI, DI...
источник

ИК

Иван Кривошеев in rannts
Байт Словович
Хм, столкнулся с проблемой.

Есть код, который в нормальном случае должен работать асинхронно. (В моем случае это обновление нескольких полей, которые берутся из thirdparty внешней системы, и таймауты там огромные могут быть, но эти поля не влияют на основной функционал, поэтому я могу позволить их обновить позже. ) Пишу вот так:
asyncio.ensure_future(xxx())

Но вот в этой xxx могут быть ошибки, и мне желательно в unittestах их все поймать, то есть чтобы тест сразу упал  надо делать синхронный вызов. Получается код аля:
coro = xxx()
if test:
   await coro
else:
  asyncio.ensure_fututre(coro)


А это как то не красиво. Понятно что можно написать обертку аля:
def ensure_future(coro):
   if test:
       await coro
   else:
      asyncio.ensure_future(coro_

ensure_future(xxx())

Это красивее, но получается что в юниттестах тестируется только один бранч в этой функции. То есть асинхронный вызов не тестируется.
Кто нить с подобным сталкивался и красиво решал?
А почему не мокнуть просто внешние вызовы для xxx(), чем такое творить? Просто такие ифчики в проде - до добра не доведут
источник

БС

Байт Словович in rannts
await coro()

тут ожидается когда coro выполнится. А мне это не надо. Пусть она в фоне работает. Но это только в продакшене. В тесте, же я хочу чтобы её можно было подождать, чтобы тест упал если в ней есть бага.
источник

БС

Байт Словович in rannts
Иван Кривошеев
А почему не мокнуть просто внешние вызовы для xxx(), чем такое творить? Просто такие ифчики в проде - до добра не доведут
конечно внешние вызовы мокаются в юниттестах. Без этого низя. И я как раз хочу в юниттестах увидеть, что вызвался не замоканный внешний вызов. ПЛюс в функция не тривиальная и в ней делается агрегация и преобразование данных. Там тоже могут быть ошибки, поэтому хочется сразу увидеть что она упала.
источник

ИК

Иван Кривошеев in rannts
Байт Словович
конечно внешние вызовы мокаются в юниттестах. Без этого низя. И я как раз хочу в юниттестах увидеть, что вызвался не замоканный внешний вызов. ПЛюс в функция не тривиальная и в ней делается агрегация и преобразование данных. Там тоже могут быть ошибки, поэтому хочется сразу увидеть что она упала.
Такое ощущение, что недостаточно на юниты разбито... Что бы по отдельности тестировать
источник

БС

Байт Словович in rannts
Да, именно. Но я не собираюсь писать юниттест на каждую свою функцию. Тесты ради тестов — не мой путь
источник

AM

Artem Malyshev in rannts
Люди уже битый час обсуждают как бы хитрее мок присунуть в рантайме... Конечно написать нормальный интерфейс будет всем плохо...
источник

ИК

Иван Кривошеев in rannts
Artem Malyshev
Люди уже битый час обсуждают как бы хитрее мок присунуть в рантайме... Конечно написать нормальный интерфейс будет всем плохо...
+1)
источник

RB

Roman Bolkhovitin in rannts
Рыцари DI, это как рыцари Ni, только DI 😊
источник

AM

Artem Malyshev in rannts
Roman Bolkhovitin
Рыцари DI, это как рыцари Ni, только DI 😊
Кого?
источник

RB

Roman Bolkhovitin in rannts
"Рыцари, которые говорят Ни", это из Монти Пайтона ))
источник
2020 January 28

KK

Kirill (Cykooz) Kuzminykh in rannts
Байт Словович
Хм, столкнулся с проблемой.

Есть код, который в нормальном случае должен работать асинхронно. (В моем случае это обновление нескольких полей, которые берутся из thirdparty внешней системы, и таймауты там огромные могут быть, но эти поля не влияют на основной функционал, поэтому я могу позволить их обновить позже. ) Пишу вот так:
asyncio.ensure_future(xxx())

Но вот в этой xxx могут быть ошибки, и мне желательно в unittestах их все поймать, то есть чтобы тест сразу упал  надо делать синхронный вызов. Получается код аля:
coro = xxx()
if test:
   await coro
else:
  asyncio.ensure_fututre(coro)


А это как то не красиво. Понятно что можно написать обертку аля:
def ensure_future(coro):
   if test:
       await coro
   else:
      asyncio.ensure_future(coro_

ensure_future(xxx())

Это красивее, но получается что в юниттестах тестируется только один бранч в этой функции. То есть асинхронный вызов не тестируется.
Кто нить с подобным сталкивался и красиво решал?
Ты уже этот вариант решения озвучил - "сохранять таску куда-то". И это есть правильное решение.
Не помню кто из "великих" и где сказал/написал, но мысль была в том, что плохо для кармы создавать таски и забывать про них. Примерно как запустить  саб-процесс и забыть про него.
Раньше asyncio ругался в дебаг режиме, при останове лупа, на таски, которые ещё работают и их никто не заавейтил или не отменил нормально.
В общем рекомендую очень стараться не бросать таски на произвол и "прибираться за собой" при завершении приложения.
В тесте тебе это помогло бы - достал бы сохранённую таску и заавейтил.
источник

KK

Kirill (Cykooz) Kuzminykh in rannts
Ну или, по аналогии с забытым саб-процессом, просто запроси у лупа все активные таски и найди среди них нужную для тебя. Правда она может уже завершится к этому моменту и ты даже не узнаешь с каким результатом.
источник

KK

Kirill (Cykooz) Kuzminykh in rannts
Сам же я стараюсь писать асинхронный код так, что бы надо было как можно реже создавать таски. Стараюсь максимально обойтись только await-ами. Если никак не решить задачу без тасков, то минимизирую контекст в котором эти таски могут быть живыми. При выходе из контекста таски либо завершаться, либо будут отменены.
источник

AS

Artem Savinov in rannts
а чисто случайно никто в ТИЗ Покровское не живет или может есть знакомые ?
источник