vladislav
Просто есть такая штука как языковой барьер
Vladislav
Просто есть такая штука как языковой барьер
И чтобы побороть его, необходимо практиковаться
Berkus
а как именно, поясни плиз
ну так тебе ж надо проверить что асинхронная операция что-то сделает, запускаешь ее в одном треде, вейт фьючура с таймаутом в основном, и вперёд
Roman
короче суть в том, что мой вопрос относится не к unit-testing'у а functional testing'у в котором доказывается верная работоспособность асинхронных сущностей.. придам пример (грубый, но пойдёт) testCase() { readFile("/this/file.txt", [](std::string result) { // will never execute ASSERT(result, expected) }); } testCase не дождётся результата и завершится, ASSERT никогда не проверится
Roman
для того чтоб тест правильно выполнился нужно изменить его немного: testCase(test) { readFile("/this/file.txt", [](std::string result) { ASSERT(result, expected) test.finish() }); }
Roman
в данном случае тест либо дождётся вызова асинхронного callback'а либо timeout'ит
Berkus
testCase() { readFile("/this/file.txt", [](std::string result) { ASSERT(result, expected) future.set(true); }); future.waitWithTimeout(); }
Berkus
в данном случае тест либо дождётся вызова асинхронного callback'а либо timeout'ит
не вижу где его просят таймаутить в данном случае, тут finish() такой же кривой костыль как done() в моче и прочем джаваскриптовом чае
Roman
библиотека которую я хочу протестить не столь проста streams.create([](handle) { handle.close("data") }) .attach([](data, handle) { ASSERT(data, "data") handle.fail("fuck") }) .failure([](error, handle) { ASSERT(error, "fuck") }) в данном случае мы создаём асинхронный объект, который при закрытии запускает при'attach'енный второй объект
Roman
короче говоря: нужно доказать, что control flow шёл правильным путём и что данные были верно переданы
Berkus
и ты пишешь для этого тестинг фреймворк?
Roman
я пытаюсь протестировать код)) но не могу найти правильный подход
Roman
т.е. создать просто несколько future'ов и ими блокировать завершение тестовой функции?
Roman
а с макросами я просто эксперементирую, может и так можно решить проблему
Roman
кстати.. почему finish() это костыль, интересен аргумент(ы)
Berkus
я бы разложил фьючеры по пути следования и в конце подождал чтобы они все стали с верными значениями
Berkus
кстати.. почему finish() это костыль, интересен аргумент(ы)
я уже не помню как оно работало в моче или в чае, но когда начали его портировать на промисы и асинхронщину, любой забытый done() превращал отладку в ад - тест мог не закончиться или закончиться с непонятной совершенно ошибкой глубоко в кишках тест фреймворка. в ++ типизация построже конечно, но лучше не делать _специальный_флаг_завершения_теста_ пушо его всяко кто-нибудь забудет вызвать в замороченном случае и будет плеваться. с твоим вложенным путем исполнения где надо finish() а где не надо? да пофиг на самом деле, он ведь асинхронный, а ожидать выполнения мы должны в основном треде если толково это делать
Roman
в моём эксперементальном решении это невозможно, ставится определённый timeout, по истечению которого кейс убивается, т.е. если кто-то где-то забыл done() вызвать то этот кейс в результатах будет помечен как fail (timeout)
Berkus
а таймаут у тебя глобальный для всех кейсов?
Berkus
что если одни асинхронные операции завершаются за 1 секунду а другие за 100?
Roman
есть default timeout, который определяется всем кейсам, да
Anonymous
У кого из них клёвые статьи по машинлернингу стоит почитать?
Вапник, Червоненкис внесли большой вклад в машинное обучение, и книги написали, втом числе и на русском есть.
Berkus
ну то есть ты не можешь сделать в одном тест кейсе три фьючера и ждать один с таймаутом 1, второй с таймаутом 10 и третий с таймаутом 100?
Roman
что если одни асинхронные операции завершаются за 1 секунду а другие за 100?
в таком случае можно определённым кейсам определять индивидуальный timeout, который перепишет default'ный
Berkus
кейсам да
Berkus
а путям внутри одного кейса?
Roman
кейс он неделимый
Berkus
ну ок, твои кейсы тебе и решать
Roman
ты ему определяешь таймаут, если кейс не завершается, например по причине забытого done(), тогда - failure (timeout)
Roman
кейсы не должны быть слишком большими, забыть done() не так легко, ибо просто будет постоянно таймаутить, а значит что-то не так
Constantine
или тестирование такое, что наличие лишнего барьера памяти все поломает?
Berkus
а нельзя такой флаг толкать как shared_ptr
это было в джаваскрипте, там нету shared_ptr в принципе
Roman
с future'ами проблема идентичная... если неправильно выставить timeout'ы или забывать завершать future... но там будет больше boiler plate кода чем с done()
Berkus
у future уже есть флаг, done() вводит глобальный стейт в тесткейсы, который в целом не нужен
Berkus
на уровне тест-фреймворка это ненужная сущность
Constantine
как вообще в плюсах можно что-то забыть
Constantine
если есть деструктор
Berkus
ты ему определяешь таймаут, если кейс не завершается, например по причине забытого done(), тогда - failure (timeout)
ты посмотри таки как регистрация тесткейсов сделана в других либах - catch, boost.test, gunit во всех есть раннеры и тест сьюты, которые делают то что тебе надо
Roman
ну так мне придётся прописывать более 3-4 future'ов и каждый закрывать, каждому таймаут ставить а done() нужно лишь раз вызвать, меньше кода
Berkus
если есть деструктор
сам тест это по факту мембер функция run() там нет деструктора
Roman
да вот, пробую, просто хочется опять-же от boilerplate'а избавиться... $Test(someTestCase) { readFile("/some/file.txt", [] (std::string result) { $AssertEqual(std::string, result, "bla") $Finish }); }
Roman
после этого: int main () { // default timeout 1000 ms testing::Test tst("My Test", {someTestCase}, 1000) tst.run(); tst.printResults(); }
Roman
но хотелось бы сократить, в $Test уже каким-то образом зарегистрировать функцию
Berkus
ну вот посмотри как BOOST_AUTO_TEST_CASE ее регистрирует например
Constantine
а я хочу, чтобы все тесты были в json :)
Berkus
но хотелось бы сократить, в $Test уже каким-то образом зарегистрировать функцию
потому что в BOOST_AUTO_TEST_CASE надо только указать имя и тело и остальная регистрация автомагическая
Vladislav
Для начала
Roman
потому что в BOOST_AUTO_TEST_CASE надо только указать имя и тело и остальная регистрация автомагическая
похоже вся магия заключается в этих вот штуках которые как скобки вокруг функций BOOST_AUTO_TEST_SUITE( test_suite1 ) BOOST_AUTO_TEST_SUITE_END()
Berkus
Он не яп
это почти джаваскрипт )
Berkus
без них прекрасно работает
Dogma
это почти джаваскрипт )
Это лишь объект из жабкаскрипта
Vladislav
он не тьюринг полный
Идрис/агда - тоже не тьюринг-полные, кстати
Vladislav
Строго говоря
Berkus
похоже вся магия заключается в этих вот штуках которые как скобки вокруг функций BOOST_AUTO_TEST_SUITE( test_suite1 ) BOOST_AUTO_TEST_SUITE_END()
минимальный тест выглядит так #define BOOST_TEST_MODULE Test_min #include <boost/test/unit_test.hpp> BOOST_AUTO_TEST_CASE(minimal) { BOOST_CHECK(true); }
Roman
без них прекрасно работает
вот я не могу понять как они это сделали... ибо регистрировать надо после декларации, но в макросе нет доступ к "после-декларации" потому-что function block не внутри макроса
Berkus
вот и загляни к ним в кишки
Berkus
всё ж есть
Berkus
я не буду за тебя гуглить сорцы буста, извини
Roman
я уже в них копаюсь))
Roman
правда найти не могу BOOST_AUTO_TEST_CASE
Roman
ща
Constantine
Он не яп
Шарите. Поэтому тесты в JSON, интерпретатор - прекомпилить
Roman
да куда они его спрятали то о_О
Constantine
Чет сложна
Нет, если уже есть парсер (на самом деле xml но пофик), который в С++ транслирует
Constantine
Тролейбус_из_хлеба.жпг
Ну нет, я не хочу пользоваться модулями из С++
Constantine
Я хочу написать //GENERATOR_USE(""_image3_dpi_aware)
Roman
документацию BOOST_AUTO_TEST_CASE нахожу без проблем, в сорсах - ни следа о_О
Constantine
И хочу написать <function-factory-visitor base="Interface"/>
Vladislav
Constantine
Х3 что там в джаве, но меня парит писать 30 виртуальных функций для каждого имени для различных классов сообщений руками