Конструктор moc что такое

Обновлено: 02.02.2023

Some of you may be wondering what a LEGO MOC is. What does MOC mean?

MOC is an acronym for My Own Creation. LEGO MOC, therefore, means LEGO My Own Creation, and are creations that have been designed and built by LEGO fans, using original LEGO bricks. These creations or MOCs as we call them, serve as proof that with imagination and a few LEGO bricks, you can build anything!

As good as most original LEGO sets are, people will always come up with amazing alternative designs for what they love. LEGO encourages and inspires people to use the parts in completely new and different ways. You can use the parts from a LEGO house set, to build something like the bee above!

Just like LEGO's own product lines, there are many different MOC categories:

Technic MOCs

These MOCs are built using LEGO Technic elements. LEGO Technic is a line which uses different components to be able to create more complex and functional structures. With rods, axles, gears and mechanical components, you are able to create complex structures such as functioning gearboxes!

Architecture MOCs

The LEGO architecture theme has a very distinct micro-scale style. The MOCs that fall within this category try to achieve the same style with different builds, such as this Harry Potter universe inspired MOC.

Harry Potter Skyline MOC

Automaton MOCs

LEGO Automaton MOCs are one of the most interesting kind of MOCs. They usually mix regular and Technic LEGO elements, to recreate a "living scene" of some sorts.

The creator TonyFlow76 is a great Automaton MOC designer, and you can view most of his designs on Youtube.

There are many other categories!

These are just a few examples of great MOC categories, but there are no limits! People can do anything they imagine, and as such, there are thousands of different MOCs out there. You can browse our catalog of ready to go kits here.

How can Build a MOC help you?

We help you get all of the original LEGO parts needed to build you MOC in one package. We deal with the difficult part for you!

When buying original LEGO sets, you are limited to a range of products that has been released by LEGO. They do a great job at designing new sets constantly, but they can't please everyone. That's why fans of LEGO started building MOCs and sharing their own designs with other fans of LEGO.

When you are able to get the design and instructions for a LEGO MOC that you want to build, you usually had to go on different websites and look for many different stores that may have the parts you need for your MOC. This can prove to be a daunting task, as you will have to deal with different sellers, shipping costs, possible problems, etc. It can also become expensive, after adding multiple extra fees, expensive parts or lost packages.

Now, in Build a MOC, we offer you the possibility to buy the whole package for the MOC you want, in one click. No need to deal with the hassle of buying LEGO online, just place your order and our specialized team will get to work on your MOC for you. You will receive all of the parts in just one package, as well as your instructions, for you to be able to just build and enjoy!

Аватар сообщества

Аватар сообщества

Аватар сообщества

Аватар сообщества

Аватар сообщества

Аватар сообщества

Аватар сообщества

Аватар сообщества

Аватар сообщества

Тенденции

Многоцелевой реактивный истребитель из набора LEGO City 60226 «Шаттл для исследований Марса»⁠ ⁠

Многоцелевой реактивный истребитель из набора LEGO City 60226 «Шаттл для исследований Марса» LEGO, Конструктор, Игрушки, Коллекция, Своими руками, Хобби, Moc, Lego City, Сборка, Альтернативная версия, Конструирование, Ideas, Креатив, Развлечения, Игры, Длиннопост, Грузовик, Гонки, Космос, Космические исследования

Это моя первая альтернативная модель которую сделал из набора Лего. Вот с этого истребителя всё и началось). Он собран из LEGO City 60226 «Шаттл для исследований Марса». Благодаря этому сету и погрузился в удивительный мир самоделок из ЛЕГО. Выкладывал ранее четвёртую сборку Полицейский катери вторую модель Гоночный грузовик.

Многоцелевой реактивный истребитель из набора LEGO City 60226 «Шаттл для исследований Марса» LEGO, Конструктор, Игрушки, Коллекция, Своими руками, Хобби, Moc, Lego City, Сборка, Альтернативная версия, Конструирование, Ideas, Креатив, Развлечения, Игры, Длиннопост, Грузовик, Гонки, Космос, Космические исследования

Для постройки истребителя использовал 74 детали из 273-х которые входят в набор.

Многоцелевой реактивный истребитель из набора LEGO City 60226 «Шаттл для исследований Марса» LEGO, Конструктор, Игрушки, Коллекция, Своими руками, Хобби, Moc, Lego City, Сборка, Альтернативная версия, Конструирование, Ideas, Креатив, Развлечения, Игры, Длиннопост, Грузовик, Гонки, Космос, Космические исследования

Вдохновлялся Российскими истребителями четвертого поколения.

Многоцелевой реактивный истребитель из набора LEGO City 60226 «Шаттл для исследований Марса» LEGO, Конструктор, Игрушки, Коллекция, Своими руками, Хобби, Moc, Lego City, Сборка, Альтернативная версия, Конструирование, Ideas, Креатив, Развлечения, Игры, Длиннопост, Грузовик, Гонки, Космос, Космические исследования

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

Многоцелевой реактивный истребитель из набора LEGO City 60226 «Шаттл для исследований Марса» LEGO, Конструктор, Игрушки, Коллекция, Своими руками, Хобби, Moc, Lego City, Сборка, Альтернативная версия, Конструирование, Ideas, Креатив, Развлечения, Игры, Длиннопост, Грузовик, Гонки, Космос, Космические исследования

Все картинки - рендеры из программы-конструктора.

И большой постер самоделки)

Многоцелевой реактивный истребитель из набора LEGO City 60226 «Шаттл для исследований Марса» LEGO, Конструктор, Игрушки, Коллекция, Своими руками, Хобби, Moc, Lego City, Сборка, Альтернативная версия, Конструирование, Ideas, Креатив, Развлечения, Игры, Длиннопост, Грузовик, Гонки, Космос, Космические исследования

Спасибо, что прочитали пост. Создавайте собственные модели - это здорово!

Моё детство примерно на 20% состояло из Dungeons & Dragons (D&D) и на 80% — из LEGO. Эти два занятия очень сильно пересекались. Мне, по разным причинам, не разрешали всё время играть в D&D. Но я, привлекая на помощь воображение, и достигнув в этом деле успехов, достойных плута 15 уровня, понял, что создание персонажей AD&D игрой не считается. Воссоздание вселенной DragonLance средствами LEGO очень хорошо помогало мне быть ближе к игре, которая мне очень нравилась.

Поэтому одним из моих любимых направлений в LEGO были замки. Я тратил многие часы, выдумывая подземелья для моих героев. Для того чтобы не терять свои находки, и из-за того, что я видел, как мои друзья в школе чертят карты подземелий, я составлял планы своих LEGO-моделей на миллиметровке. Кроме того, я пытался сохранить и сведения о том, как именно были устроены модели. Использование миллиметровки казалось логичным для изображения того, что, в основном, состояло из прямоугольных блоков. Но меня, в итоге, сгубило недостаточно хорошее понимание правил изометрической проекции.


Теперь, хоть я и стал старше, моя любовь к LEGO не угасла. И хотя я и не могу сказать, что очень уж горжусь своими моделями (их называют MOC-моделями), я почувствовал, что просто должен разобраться с тем, как мне документировать то, что создаю. Я никогда не умел очень уж хорошо рисовать. Поэтому я решил обратиться к компьютеру.

CAD для LEGO

Несколько лет я работал в сфере виртуального 3D-моделирования (а в сфере обычного 3D — и того больше). Я хорошо владею 3D-приложениями, но всё, чем я пользовался, заточено под анимированную графику и под производство фильмов. Все эти программы, как, собственно, и фильмы, рассчитаны на то, чтобы создать красивую картинку. Как именно что-то сделано, до тех пор, пока всё выглядит хорошо, не так уж и важно. Если, ради того, чтобы что-то выглядело бы очень хорошо, нужно «обмануть» законы физики, то это вполне приемлемо, так как это будет существовать только в виртуальном пространстве.

А вот системы автоматизированного проектирования (Computer-Aided Design, CAD), это уже нечто другое. CAD-приложения пришли на смену обычным чертежам. В них создают спецификации, иллюстрирующие то, как нечто может быть создано в реальном мире. От этих программ ждут точности и реализма.

Так как невероятно много людей увлечено LEGO, существует активное сообщество тех, кто создаёт LEGO-модели, используя CAD-программы. Преимущества такого подхода очевидны: можно задокументировать подробные сведения о модели, описать то, какие детали нужны для её создания, и то, как именно их нужно соединить друг с другом. Это, конечно, не замена реальному конструктору LEGO (ну, разве что для тех, кто любит CAD больше, чем LEGO), но это — отличное дополнение к хобби.

Для того чтобы построить виртуальную модель LEGO, нужны две вещи:

  • Виртуальные детали LEGO.
  • CAD-приложение.

Виртуальные детали LEGO

Для того чтобы раздобыть виртуальное представление практически любого из когда-либо созданных строительных блоков для LEGO-моделей, можете воспользоваться опенсорсным ресурсом LDraw. LDraw — это открытый стандарт для цифровых моделей LEGO, который включает в себя возможности по описанию размеров и ориентации элементов. В дополнение к работе по описанию деталей средствами LDraw, силами сообщества подготовлены 3D-модели для каждой детали. Это значит, что все желающие могут загрузить тысячи определений деталей, истратив на это не особенно много трафика.

Установка набора деталей

Виртуальные детали очень похожи на изображения, которые используются на сайтах, или на шрифты, применяемые на компьютере. Собственно говоря, соответствующие файлы можно хранить где угодно. Главное, чтобы приложение, в котором планируется работать с деталями, знало о том, где эти файлы находятся. В Linux LDraw-файлы обычно размещают в папке /usr/share/LDRAW . В Windows это обычно C:\Users\Public\Documents\LDraw .

LDraw даёт в наше распоряжение лишь спецификации для каждой детали. Вот, например, как выглядит код описания кубика 1x1:


Для того чтобы увидеть детали в более привычном облике, понадобится программа для их визуализации.

Приложение LDView для визуализации деталей

LDView — это среда для 3D-рендеринга, напоминающая POV-Ray или Cycles из Blender. Это приложение создано специально для рендеринга .ldr-файлов, то есть — CAD-файлов, содержащих данные в формате LDraw.

Если вы работаете на Linux, то, возможно, вы найдёте LDView в своём репозитории ПО. Если в репозитории этой программы не окажется — вы можете скачать установщик с сайта проекта. Если вы пользуетесь macOS или Windows, то вам, опять же, нужно будет воспользоваться сайтом LDView.

Просмотр отдельной детали

Легче всего начать цифровое конструирование моделей LEGO, попытавшись визуализировать отдельную деталь.

Сначала откройте ваш любимый текстовый редактор. Это может быть любая программа. Главное — чтобы она могла сохранять документы в виде обычного текста. Некоторые текстовые редакторы, в стремлении оказать пользователям добрую услугу, пытаются сохранять текстовые материалы в файлах, в которых, помимо текстов, есть ещё масса служебной информации (вроде .rtf и .doc). Существует множество хороших кросс-платформенных текстовых редакторов. Я, для наших дел, могу порекомендовать довольно-таки минималистичный редактор Geany.

Создадим новый файл с именем 1brick.ldr и введём в него следующий текст:


А теперь взглянем на наше скромное творение:


Только что вы создали простой CAD-файл, описывающий один кубик (а именно — модель номер 3001), цветовой индекс которого равняется 1 (это синий цвет), расположенный в позиции (0, 0, 0) по осям X, Y и Z. Поворот кубика регулируется с использованием средств матричного преобразования. Их применение, надо признать, не относится к простым математическим вычислениям. Правда, при конструировании LEGO-моделей произвольное вращение деталей требуется сравнительно редко, так как большинство деталей стыкуются друг с другом с использованием шипов.

Любая строка в файле, начинающаяся с 0, содержит либо комментарий, либо метаданные. Строка, начинающаяся с 1, содержит описание детали.

Вы можете попрактиковаться в перемещении и вращении деталей, внося изменения в свой CAD-файл. Обычный кубик имеет в высоту 24 LDU (LDraw Units). Это значит, что ставить детали друг на друга можно, меняя их координату Y с шагом в 24 единицы. Поворачивать детали можно, выполняя матричные преобразования.

Взгляните на этот код:


Вот результат его визуализации.


Конечно, перемещать детали можно вдоль любой из трёх осей. В спецификации LDraw сказано, что кубик 1x1 имеет 20 LDU в ширину и 20 LDU в длину. А это значит, что расставлять такие кубики вдоль оси X можно, меняя их позиции с шагом в 20 LDU.


Ещё два кубика

Порядок сборки модели

Чаще всего формат LDraw используется для того чтобы продемонстрировать порядок сборки модели. А это значит, что нужно описать последовательность шагов сборки. В LDraw это делается с использованием метакоманды STEP .

Для того чтобы испытать эту метакоманду, добавьте в свой файл, между описаниями деталей, следующее:


Готовый файл будет выглядеть так:


Теперь в вашем проекте описано два шага. На первом выводится первый кубик, на втором — второй. Можно пошагово просматривать .ldr-файлы, пользуясь клавишами-стрелками в верхней панели инструментов LDView, находящимися около подписи Steps .


Панель инструментов для пошаговой визуализации моделей

На одном шаге необязательно должен выводиться лишь один кубик. Как и в случае с инструкциями к наборам LEGO, установку нескольких деталей можно объединить в один шаг. Главное, чтобы это не повредило понятности инструкции.

В LDraw есть и другие команды. Например — тут можно рисовать линии, поясняющие расположение деталей, и делать прочие подобные вещи. Соответствующие сведения можно найти в спецификации.

Выяснение кодов деталей

Я хранил свою коллекцию LEGO в ящиках для рыболовных принадлежностей. Поэтому я мог быстро найти любую деталь из любого набора. Правда, по мере того, как росла коллекция, мне было нужно всё больше и больше ящиков. А в результате у меня стало уходить больше времени на поиск нужной детали.

Если учесть то, что в LEGO имеется более 11000 уникальных деталей, искать цифровые детали так же сложно, как и обычные. У каждой официальной детали LEGO есть собственный код. Например, тот кубик 2x4, который мы использовали в примере, имеет код 3001. Если вам известен код детали, вы можете просто использовать его в CAD-файле, и соответствующая деталь появится в вашей модели.

В дистрибутиве LDraw имеется файл parts.lst , в котором, с помощью grep, можно найти нужную деталь. Но детали там не всегда описаны по одной и той же схеме. Работая с этим файлом не всегда легко предугадать то, какие именно ключевые слова соответствуют тем или иным деталям. Например — как понять, какое слово, «curved» «sloped» или «angled», лучше всего характеризует некую деталь сложной формы?

Хотя искать детали можно и в parts.lst , в этом деле нам могут помочь некоторые специальные интернет-ресурсы:

    — это пользовательская группа, в которой есть база данных со сведениями о кодах деталей LEGO, построенная на основе сведений, взятых из LDraw. — хороший каталог деталей. — ещё один ресурс, на котором есть каталог деталей.

Другие средства для рендеринга моделей

После того, как вы создали свой шедевр, LDView может экспортировать вашу модель, что позволит вам отрендерить её в высоком качестве. Для этого можно воспользоваться POV-Ray — опенсорсной программой для фотореалистичного рендеринга трёхмерных моделей. В результате плоды ваших трудов можно будет представить в весьма привлекательном виде. Найти POV-Ray можно или в репозитории программ вашего дистрибутива Linux, или на сайте проекта.

Вот пример команды рендеринга:


Ниже показан результат визуализации.


Высококачественная визуализация модели

Если вам нужна программа для формирования инструкций по сборке моделей — попробуйте опенсорсную LPub3D. Эта программа выводит пошаговые инструкции и список деталей, необходимых на каждом шаге.


Исследование мира LEGO

Создание моделей из деталей LEGO — это интересно. Разработка собственных моделей — это воплощение той творческой энергии, которой фанаты LEGO заряжаются, занимаясь любимым делом. Теперь ваши LEGO-идеи больше не должны существовать лишь в форме бесплотных идей. Вы можете сохранить их в виде моделей и пошаговых инструкций.

Мир любителей LEGO — это приятное и креативное место, которое стоит посетить всем тем, кому нравится создавать цифровые модели, разрабатывать собственные детали, или делать с кубиками LEGO что-то такое, чего никто больше с ними не делает. Если вам нравится LEGO, то сегодня — самый лучший день для того чтобы стать частью LEGO-сообщества!

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

Вступление

Moc — это один из инструментов разработчика и часть библиотеки Qt. Его задача — поддерживать расширение языка С++, необходимое для интроспекции и рефлексии в Qt (сюда относятся сигналы, слоты и QML). Для более детального объяснение вы можете почитать о том, как работают сигналы и слоты в Qt.

Необходимость использования moc является одним из главных объектов критики Qt. Это даже привело к появлению форков Qt, принципиально отказавшихся от moc (например, CopperSpice). Но всё-же большинство приписываемых moc так называемых недостатков не обоснованы.

Moc переписывает ваш код перед тем, как передать его компилятору

Это распространённое заблуждение. Moc не модифицирует и не переписывает ваш код. Он просто парсит часть кода для того, чтобы сгенерировать дополнительные С++ файлы, которые потом будут компилироваться независимо. Это не очень большое отличие, но всё-же важное техническое недопонимание.

Moc просто автоматически генерирует шаблонный код, который можно было бы долго и нудно писать вручную, если бы moc не существовало. Если вы мазохист, то и сейчас вполне возможно взять и написать самостоятельно все таблицы для интроспекции и реализации сигналов. Ну или положиться на надёжный инструмент, который сделает это за вас.

Используя Qt, вы не пишете на настоящем С++

Я слышал этот довод много раз, но он попросту неверен. Макросы, используемые moc для аннотации кода — это стандартные макросы С++. Они должны быть корректно распознаны любым инструментом, способным анализировать код на С++. Когда вы добавляете в код Q_OBJECT, то просто дописываете объявление нескольких функций. Когда вы пишете «signals:», то просто добавляете макрос, который превратится в «public:». Многие другие макросы Qt вообще ни во что не раскрываются. Moc просто находит их и генерирует код эмиттеров сигналов и таблиц интроспекции.

Тот факт, что ваш код теперь может быть прочитан ещё одним инструментом, не делает его «менее соответствующим стандарту С++». Вы же не считаете код, написанный с расчётом на использование gettext или doxygen каким-то «менее правильным С++»?

Moc усложняет процесс сборки кода

Если вы используете любую промышленную систему сборки кода, вроде CMake или qmake, то получаете нативную поддержку Qt. Даже с какой-то собственной системой сборки речь идёт о всего-лишь одном дополнительном запуске команды обработки заголовочных файлов. Все известные мне системы сборки позволяют добавлять шаги по запуску дополнительных команд перед запуском компилятора, поскольку многие проекты в том или ином виде используют генерацию кода при сборке проекта. Вспомните, например, инструменты вроде yacc/bison, gperf, llvm/TableGen.

Moc делает отладку сложнее

Поскольку moc генерирует код на чистом С++, то отладчики не должны иметь никаких проблем с ним. Мы стараемся поддерживать сгенерированный код в таком состоянии, чтобы он не вызывал предупреждений компиляторов или инструментов статического или динамического анализа кода. Да, иногда при отладке вы будете видеть в колстеке следы сгенерированного moc кода. В некоторых редких случаях вы можете получить ошибку, связанную с кодом, созданным moc, но обычно причины достаточно легко обнаружить. Код, сгенерированный moc, достаточно человекочитаем. Также его, вероятно, понимать и отлаживать даже проще, чем те печально известные ошибки некоторых библиотек, построенных на продвинутом использовании шаблонов.

Отказ от moc улучшает производительность на этапе выполнения кода

Это прямая цитата с главной страницы CopperSpice, и, вероятно, самая большая их ложь. Код, генерируемый moc, старается избегать динамических аллокаций и уменьшить количество реаллокаций памяти. Генерируемые moc таблицы являют собой константные массивы и хранятся в read-only сегменте данных. CopperSpice же регистрирует свои QMetaObject (информацию о сигналах, слотах и свойствах) на рантайме.

Milian Wolff проделал некоторые сравнения производительности Qt и CopperSpice в его докладе на CppCon2015. Вот скриншот одного из его слайдов (меньше — лучше).

image

Также нужно отметить, что код на Qt даже с учётом запуска moc компилируется быстрее, чем код на CopperSpice.

Устаревшие мифы

Некоторая критика когда-то была справедливой, но более таковой не является.

Макрос не может быть использован при объявлении сигнала, слота, базового класса объекта, а также .

До выхода Qt5 утилита moc действительно не раскрывала макросы. Но начиная с Qt 5.0 moc полностью поддерживает макросы во всех вышеперечисленных местах, так что это больше совершенно не является проблемой.

Перечисления (enums) и переопределения типов (typedefs) должны строго соответствовать при использовании их в качестве параметров сигналов и слотов

Это является проблемой только если вы всё ещё хотите использовать синтаксис соединений, основанный на строках (поскольку там действительно используется прямое сравнение названий типов). С выходом Qt5 и новым синтаксисом это больше не препятствие.

Q_PROPERTY не позволяет использовать запятые в типах

Другая критика

Шаблоны, вложенные классы или классы, используемые множественное наследование, не могут быть QObject-ами

Хотя это и является правдой, но эти возможности просто пока не поддерживаются QObject, хотя и вполне могут быть реализованы в moc, если мы этого захотим. Проект Qt в данный момент не считает данные фичи приоритетными.

Я однажды добавил поддержку шаблонных QObjects в moc, но это изменение не вошло в основную ветку разработки, поскольку никто больше не выразил интереса к данной функциональности.

Ещё нужно отметить поддержку шаблонных и вложенных классов в moc-ng.

Множественное наследование уже само по себе является очень неоднозначным. Чаще всего оно указывает на проблемы с архитектурой приложения и многие современные языки напрямую его запрещают. Вы всё ещё можете использовать множественное наследование с Qt, если если QObject является первым базовым классом в цепочке наследования. Это небольшое ограничение позволяет нам применять полезные оптимизации. Когда-нибудь задумывались почему qobject_cast настолько быстрее, чем dynamic_cast?

Выводы

Я не думаю, что moc — это проблема. Макросы Qt действительно помогают реализовать необходимую Qt функциональность. Сравнивая их с подходом CopperSpice мы можем заметить в последнем значительную избыточность служебного кода, а также недружелюбный синтаксис макросов (не говоря уже о потерях производительности на рантайме). Синтаксис сигналов и слотов, который существует в Qt с 90-ых годов — одна из фундаментальных вещей, обеспечивших успех фреймворка.

Вам может быть также интересно изучить некоторые эксперименты, связанные с moc, вроде moc-ng (это moc, переписанный с использованием библиотек clang). Также есть вот это исследование замены moc с помощью инструментов рефлексии С++. Ну и библиотека Verdigris, с макросами, создающими QMetaObject без moc.

Наверное каждый, кто начинал писать юнит и интеграционные тесты, сталкивался с проблемой злоупотребления моками, которая приводит к хрупким тестам. Последние, в свою очередь, создают у программиста неверное убеждение в том, что тесты только мешают работать.

Ниже представлен вольный перевод статьи, в которой José Valim — создатель языка Elixir — высказал своё мнение на проблему использования моков, с которым я полностью согласен.

Несколько дней назад я поделился своими мыслями по поводу моков в Twitter:


Мок — полезный инструмент в тестировании, но имеющиеся тестовые библиотеки и фреймворки зачастую приводят к злоупотреблению этим инструментом. Ниже мы рассмотрим лучший способ использования моков.

Что такое мок?

Воспользуемся определением из англоязычной википедии: мок — настраиваемый объект, который имитирует поведение реального объекта. Я сделаю акцент на этом позже, но для меня мок — это всегда существительное, а не глагол [для наглядности, глагол mock везде будет переводиться как "замокать" — прим. перев.].

На примере внешнего API

Давайте рассмотрим стандартный пример из реальной жизни: внешнее API.

Представьте, что вы хотите использовать Twitter API в веб-приложении на фреймворке Phoenix или Rails. В приложение приходит запрос, который перенаправляется в контроллер, который, в свою очередь, делает запрос к внешнему API. Вызов внешнего API происходит прямо в контроллере:

Далее вы используете такой же подход в других частях приложения и добиваетесь прохождения юнит и интеграционных тестов. Время двигаться дальше?

Кроме того, так как мок, показанный выше, изменяет модуль глобально, вы больше не сможете запустить эти тесты в Elixir параллельно.

Решение

В Elixir все приложения имеют конфигурационные файлы и механизм для их чтения. Используем этот механизм, чтобы настроить клиент Twitter'a для различных окружений. Код контроллера теперь будет выглядеть следующим образом:

Соответствующие настройки для различных окружений:

Необходимость явных контрактов

Мок предназначен для замены реального объекта, а значит будет эффективен только в том случае, когда поведение реального объекта определено явно. Иначе, вы можете оказаться в ситуации, когда мок начнет становиться все сложнее, увеличивая зависимость между тестируемыми компонентами. Без явного контракта заметить это будет сложно.

Мы уже имеем три реализации Twitter API и лучше сделать их контракты явными. В Elixir описать явный контракт можно с помощью behaviour:

Теперь добавьте @behaviour MyApp.Twitter в каждый модуль, который реализует этот контракт, и Elixir поможет вам создать ожидаемый API.

В Elixir мы полагаемся на такие behaviours постоянно: когда используем Plug, когда работаем с базой данных в Ecto, когда тестируем Phoenix channels и так далее.

Тестирование границ

Сначала, когда явные контракты отсутствовали, границы приложения выглядели так:

[MyApp] -> [MyApp.Twitter (contract)]

Сложность тестирования больших систем заключается в определение четких границ между компонентами. Слишком высокий уровень изоляции при отсутствии интеграционных тестов сделает тесты хрупкими, а большинство проблем будут обнаруживаться только на production. С другой стороны, низкий уровень изоляции увеличит время прохождения тестов и сделает тесты сложными в сопровождении. Единственного верного решения нет, и уровень изоляции будет изменяться в зависимости от уверенности команды и прочих факторов.

Исключим тесты с Twitter API:

При необходимости включим их в общий тестовый прогон:

mix test --include twitter_api

Также можно запустить их отдельно:

mix test --only twitter_api

Примечания

Я бы хотел закончить эту статью разбором нескольких общих проблем, которые всплывают практически в каждом обсуждении моков.

Создание "тестируемого" кода

Получается, предложенное решение делает production-код более "тестируемым", но создает необходимость ходить в конфигурацию приложения на каждый вызов функции? Наличие ненужного оверхэда, чтобы сделать что-то "тестируемым", не похоже на хорошее решение.

Я бы сказал, что речь идет не о создании "тестируемого" кода, а об улучшении дизайна [от англ. design of your code — прим. перев.].

Тест — это пользователь вашего API, как и любой другой код, который вы пишите. Одна из идей TDD заключается в том, что тесты — это код и ничем не отличаются от кода. Если вы говорите: "Я не хочу делать мой код тестируемым", это означает "Я не хочу уменьшать зависимость между компонентами" или "Я не хочу думать о контракте (интерфейсе) этих компонентов".

Нет ничего плохого в нежелании уменьшать зависимость между компонентами. Например, если речь идет о модуле работы с URI [имеется ввиду модуль URI для Elixir — прим. перев.]. Но если мы говорим о чем-то таком же сложном, как внешнее API, определение явного контракта и наличие возможности заменять реализацию этого контракта сделает ваш код удобным и простым в сопровождении.

Кроме того, оверхэд минимален, так как конфигурация Elixir-приложения хранится в ETS, а значит вычитывается прямо из памяти.

Локальные моки

Хотя мы и использовали конфигурацию приложения для решения проблемы с внешним API, иногда проще передать зависимость как аргумент. Например, некоторая функция выполняет долгие вычисления, которые вы хотите изолировать в тестах:

Можно избавиться от зависимости, передав её как аргумент. В данном случае будет достаточно передачи анонимной функции:

Тест будет выглядеть следующим образом:

Или, как было описано ранее, можно определить контракт и передать модуль целиком:

Вы также можете представить зависимость в виде data structure и определить контракт с помощью protocol.

Передать зависимость как аргумент намного проще, поэтому, если возможно, такой способ должен быть предпочтительнее использования конфигурационного файла и Application.get_env/3 .

Мок — это существительное

Лучше думать о моках как о существительных. Вместо того, чтобы мокать API (мокать — глагол), нужно создать мок (мок — существительное), который реализует необходимый API.

Большинство проблем от использования моков возникают, когда они используются как глаголы. Если вы мокаете что-то, вы изменяете уже существующие объекты, и зачастую эти изменения являются глобальными. Например, когда мы мокаем модуль SomeDependency , он изменится глобально:

При использовании мока как существительного, вам необходимо создать что-то новое, и, естественно, это не может быть уже существующий модуль SomeDependency . Правило "мок — это существительное, а не глагол" помогает находить "плохие" моки. Но ваш опыт может отличаться от моего.

Библиотеки для создания моков

После прочитанного у вас может возникнуть вопрос: "Нужно ли отказываться от библиотек для создания моков?"

Все зависит от ситуации. Если библиотека подталкивает вас на подмену глобальных объектов (или на использование моков в качестве глаголов), изменение статических методов в объектно-ориентированном или замену модулей в функциональном программировании, то есть на нарушение описанных выше правил создания моков, то вам лучше отказаться от неё.

Однако, есть библиотеки для создания моков, которые не подталкивают вас на использование описанных выше анти-паттернов. Такие библиотеки предоставляют "мок-объекты" или "мок-модули", которые передаются в тестируемую систему в качестве аргумента и собирают информацию о количестве вызовов мока и о том, с какими аргументами он был вызван.

Заключение

Одна из задач тестирования системы — нахождение правильных контрактов и границ между компонентами. Использование моков только в случае наличия явного контракта позволит вам:

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

Читайте также: