Ни разу не постил на Хабр, а тут такой интересный повод нарисовался.
Вопросы, обсуждаемые в статье:
Сразу скажу, что я любитель находить баги, а баги любят находить меня. И 13 число в моей жизни играет не последнюю роль.
Итак, сижу я вечером (на дворе как раз 13 декабря), тружусь над одним из своих любимых продуктов xUnitFor1C над значимым релизом 4.0
Тестирую работу тестов в режиме управляемого приложения при переходе с клиента на сервер и обратно.
Есть у нас один интересный и непростой сценарий поведения при использовании серверных тестов в режиме управляемого приложения на тонком клиенте.
В модуле контекста ядра тестирования (Упр.форма) созданы 2 похожих метода ВыполнитьТестовыйМетодНаКлиенте (признак &НаКлиенте) и ВыполнитьТестовыйМетодНаСервере (признак &НаСервере).
Назначение их понятно из названия.
Обычно в тесте я использовал метод УпрФорма.ВыполнитьТестовыйМетодНаКлиенте для проверки тестов УФ, т.е. через контекст управляемой формы.
Все штатно, проблем нет.
Но теперь мне понадобилось проверить переход с клиента на сервер. Я решил, что хватит использовать ВыполнитьТестовыйМетодНаКлиенте, пора заняться более глубоким хакингом и вызвал метод ВыполнитьТестовыйМетодНаСервере.
Написал специальный тест, описал поведение согласно сценария и внутри теста вызываю ЭтаФорма.ВыполнитьТестовыйМетодНаСервере.
Тест предсказуемо падает, ведь я работаю по методике TDD. Начинаю разбираться, что нужно поправить в коде, чтобы тест заработал (ТДД работает именно так).
Проходит несколько минут, и я с огромным изумлением вижу, что вызываемой мной метод ВыполнитьТестовыйМетодНаСервере является приватным, т.е. у него нет признака Экспорт!
При этом я его успешно вызываю, и он прекрасно отрабатывает.
Не верю своим глазам, ведь я много умных книжек читал, знаю много языков программирования, и понимаю, что приватный метод просто так вызвать нельзя.
Сначала я проверил, вызываю я правильный код из правильного места и т.д. Еще через пару минут я убедился, что ошибки нет, действительно, я вызываю приватный метод и он успешно отрабатывает!
Также я проверил, что метод ВыполнитьТестовыйМетодНаКлиенте является публичным/экспортным методом.
Согласно методикам поиска багов я максимально упростил ситуацию и исключил сторонние факторы:
создал отдельную внешнюю обработку. Добавил к ней простую управляемую форму.
Добавил 2 команды ВызовПриватногоКлиентскогоМетода и ВызовПриватногоСерверногоМетода
Для этой формы добавил следующий код:
Первоначально я запускал подобный ручной тест на свежайшей версии 8.3.7.1805 (выпущена 10.12.2015, если я не ошибаюсь).
Получаю поведение:
В итоге получаем явный баг в 8.3.7.
Далее я согласно тем же методикам поиска багов проверяю поведение на другой платформе 1С 8.2.19
Поведение абсолютно такое же.
Проверил поведение на встроенной обработке, те же проблемы.
Собственно, формулировка бага — сторонний код может вызвать приватный серверный метод управляемой формы через контекст управляемой формы, а приватный клиентский код таким образом вызвать нельзя.
В итоге этот баг сделал мой вечер!
Надеюсь, и вам понравилась указанная багофича.
Ух, как теперь можно развернуться кодерам на языке 1С, теперь можно экспорт не писать, все и без него работает.
Это же сколько кода можно наваять, если не тратить время на написание Экспорт! А в масштабах страны какая экономия времени?
А если более серьезно, то хочется обратиться к 1С для исправления данной ошибки.
Евангелист 1С PeterG, что скажешь?
Также предлагаю встроить в продукт АПК (Автоматизированная проверка конфигурации) проверку на подобный баг.
PS Если кому-то нужно, могу дать обработку для ручного тестирования.
PPS А если кому интересно, что же нового будет в версии 4.0 xUnitFor1C, ждите следующей статьи и новогоднего подарка!
Вопросы, обсуждаемые в статье:
- Выбрать публичность или приватность — вот в чем вопрос;
- Кто главнее — клиент или сервер?
- Прочтите статью и вы увидите, как на эти вопрос отвечает 1С в своей платформе;
- И еще неожиданный интересный факт о Google узнают те, кто дочитает до конца;
- Я кратко расскажу, как я нашел точного виновника бага.
Сразу скажу, что я любитель находить баги, а баги любят находить меня. И 13 число в моей жизни играет не последнюю роль.
История
Итак, сижу я вечером (на дворе как раз 13 декабря), тружусь над одним из своих любимых продуктов xUnitFor1C над значимым релизом 4.0
Тестирую работу тестов в режиме управляемого приложения при переходе с клиента на сервер и обратно.
Есть у нас один интересный и непростой сценарий поведения при использовании серверных тестов в режиме управляемого приложения на тонком клиенте.
В модуле контекста ядра тестирования (Упр.форма) созданы 2 похожих метода ВыполнитьТестовыйМетодНаКлиенте (признак &НаКлиенте) и ВыполнитьТестовыйМетодНаСервере (признак &НаСервере).
Назначение их понятно из названия.
Обычно в тесте я использовал метод УпрФорма.ВыполнитьТестовыйМетодНаКлиенте для проверки тестов УФ, т.е. через контекст управляемой формы.
Все штатно, проблем нет.
Но теперь мне понадобилось проверить переход с клиента на сервер. Я решил, что хватит использовать ВыполнитьТестовыйМетодНаКлиенте, пора заняться более глубоким хакингом и вызвал метод ВыполнитьТестовыйМетодНаСервере.
Написал специальный тест, описал поведение согласно сценария и внутри теста вызываю ЭтаФорма.ВыполнитьТестовыйМетодНаСервере.
Тест предсказуемо падает, ведь я работаю по методике TDD. Начинаю разбираться, что нужно поправить в коде, чтобы тест заработал (ТДД работает именно так).
Проходит несколько минут, и я с огромным изумлением вижу, что вызываемой мной метод ВыполнитьТестовыйМетодНаСервере является приватным, т.е. у него нет признака Экспорт!
При этом я его успешно вызываю, и он прекрасно отрабатывает.
Поиск и подтверждение бага в платформе 1С
Не верю своим глазам, ведь я много умных книжек читал, знаю много языков программирования, и понимаю, что приватный метод просто так вызвать нельзя.
Сначала я проверил, вызываю я правильный код из правильного места и т.д. Еще через пару минут я убедился, что ошибки нет, действительно, я вызываю приватный метод и он успешно отрабатывает!
Также я проверил, что метод ВыполнитьТестовыйМетодНаКлиенте является публичным/экспортным методом.
Согласно методикам поиска багов я максимально упростил ситуацию и исключил сторонние факторы:
создал отдельную внешнюю обработку. Добавил к ней простую управляемую форму.
Добавил 2 команды ВызовПриватногоКлиентскогоМетода и ВызовПриватногоСерверногоМетода
Для этой формы добавил следующий код:
&НаСервере
Процедура ПриватнаяНаСервере()
Сообщить("ПриватнаяНаСервере");
Сообщить("После вызова ПриватнаяНаСервере");
КонецПроцедуры
&НаКлиенте
Процедура ВызовПриватногоСерверногоМетода(Команда)
ЭтаФорма.ПриватнаяНаСервере(); // не выдает ошибку !!
КонецПроцедуры
&НаКлиенте
Процедура ПриватнаяНаКлиенте()
Сообщить("ПриватнаяНаКлиенте");
КонецПроцедуры
&НаКлиенте
Процедура ВызовПриватногоКлиентскогоМетода(Команда)
ЭтаФорма.ПриватнаяНаКлиенте(); // как и положено, выдает исключение
Сообщить("После вызова ПриватнаяНаКлиенте");
КонецПроцедуры
Первоначально я запускал подобный ручной тест на свежайшей версии 8.3.7.1805 (выпущена 10.12.2015, если я не ошибаюсь).
Получаю поведение:
- приватный серверный метод успешно вызывается, сообщения отрабатывают. Это ошибка.
- с приватным клиентским методом проще. Выдается правильное исключение, что метод не обнаружен.
{Форма.Форма.Форма(15)}: Метод объекта не обнаружен (ПриватнаяНаКлиенте)
ЭтаФорма.ПриватнаяНаКлиенте();
В итоге получаем явный баг в 8.3.7.
Далее я согласно тем же методикам поиска багов проверяю поведение на другой платформе 1С 8.2.19
Поведение абсолютно такое же.
Проверил поведение на встроенной обработке, те же проблемы.
Собственно, формулировка бага — сторонний код может вызвать приватный серверный метод управляемой формы через контекст управляемой формы, а приватный клиентский код таким образом вызвать нельзя.
Риторические вопросы
- Получается, это не баг, это фича, потому что подобное «странное» поведение наблюдается очень давно, уже несколько лет?
- А как же приватность/публичность? это же базовые принципы!
- А как же инкапсуляция? получается, что кто угодно может вызвать скрытые серверные методы и нарушить поведение.
- А как же равноправие? почему клиент настолько ущемлен по сравнению с сервером :) ?
В итоге этот баг сделал мой вечер!
Надеюсь, и вам понравилась указанная багофича.
Ух, как теперь можно развернуться кодерам на языке 1С, теперь можно экспорт не писать, все и без него работает.
Это же сколько кода можно наваять, если не тратить время на написание Экспорт! А в масштабах страны какая экономия времени?
А если более серьезно, то хочется обратиться к 1С для исправления данной ошибки.
Евангелист 1С PeterG, что скажешь?
Также предлагаю встроить в продукт АПК (Автоматизированная проверка конфигурации) проверку на подобный баг.
PS Если кому-то нужно, могу дать обработку для ручного тестирования.
PPS А если кому интересно, что же нового будет в версии 4.0 xUnitFor1C, ждите следующей статьи и новогоднего подарка!
А причем здесь Google?
PPPS при поиске картинки для статьи обнаружил, что при поиске картинок в Гугл для фразы «нарушение приватности» больше всего картинок с логотипом именно Google. К чему бы это?
Melex
Не понял позыв статьи.
Вы работаете в контексте текущей формы, почему вам не должны быть доступны эти функции?
Вот если бы вы могли вызывать таким образом приватные функции из другой формы, тогда я еще бы понял, этого дико не хватает при написании механизмов добавления строк в типовые документы, так как там все функции перерасчета — приватные.
На проводки ничего не повлияет, так как проводки делаются непосредственно в самом модуле документа, а не его формы. Так что тут все чисто.
Вот раньше, в 8.3.5 (вроде еще можно было), я мог создать две функции с одним именем, и в зависимости от контекста — я получал соответствующий вызов нужной функции, вот это было удобно, не надо было лепить кучу модулей Клиент, Сервер, КлиентСервер :) Но эту фичу починили :(
artbear
Нет, я работаю именно через контекст управляемой формы.
У меня как раз все было хуже, т.к. вызов идет из другой формы — из формы раннера тестов вызываются методы другой управляемой формы.
А здесь странность — почему приватные клиентские методы нельзя вызывать, а приватные серверные можно?