Foundry: итоговая лаборатория тестирования Solidity
В предыдущем уроке мы определили происхождение артефакта. Теперь соберём лабораторию целиком. За тридцать уроков отдельные фрагменты развивались: handler получил роли, независимую модель и учёт действий, а invariant-файл сменил прямую цель на программу истории.
Итоговый архив исходников содержит согласованную последнюю редакцию. Он подготовлен как текстовый комплект: компиляция, примеры, тесты, fork, покрытие и измерение газа не выполнялись. Зависимости не установлены. Эта граница указана и здесь, и в README, чтобы ожидания не превратились в выдуманный отчёт об успехе.
Что входит в комплект
Основной прикладной тип остаётся CourseCatalog из второго урока. Он хранит текущий отпечаток и активность, разрешает издателю заменять выпуск и сохраняет digest при отключении. API не получает скрытых методов версий, оплаты или передачи роли ради удобства отдельных глав.
CourseReader и CourseObserver являются самостоятельными расширениями. Первый трактует активный ненулевой ответ зависимости, второй сохраняет момент наблюдения. Благодаря разделению можно изучать mock и временные условия, не приписывая базовому реестру внешние вызовы и сроки действия, которых в нём нет.
| Каталог или файл | Назначение |
|---|---|
src/CourseCatalog.sol |
Базовый договор реестра |
src/CourseReader.sol |
Отдельная обработка внешнего ответа |
src/CourseObserver.sol |
Отдельная модель возраста наблюдения |
test/CourseCatalog.t.sol |
Unit, fuzz, модель короткой истории и регрессия |
test/handlers/CatalogHandler.sol |
Разрешённые и чужие действия над 1..20 |
test/CourseCatalogInvariant.t.sol |
Согласованность выпуска, роли и учёта |
examples/CourseCatalogLocalFork.t.sol |
Необязательный локальный снимок |
В комплект не включён намеренно ошибочный delete из двадцать четвёртого урока. Он служил разбору контрпримера и не должен оказаться в правильной базовой реализации. Также промежуточный handler без модели заменён последним вариантом, а не сохранён как второй конкурирующий источник ожиданий.
Почему нельзя просто склеить все листинги
Некоторые уроки заменяли setUp или тело функции, а не добавляли ещё одну версию рядом. Механическое объединение породило бы одинаковые имена методов, конфликтующие цели и смешанные роли. Итоговый файл оставляет одну согласованную подготовку и один набор действий.
Обычный CourseCatalogTest по-прежнему начинается с нового пустого реестра. Набор observer имеет собственную предварительную публикацию, потому что ему требуется успешное чтение. Эта подготовка не переносится в общий unit-файл, где иначе исчезла бы проверка пустого состояния.
В финальном handler конструктор дополнительно сверяет адрес издателя с getter реестра и требует его отличия от читателя. Эти проверки относятся к согласованности лаборатории. Они не меняют прикладной CourseCatalog и не являются системой управления настоящими ключами.
Сохраняем несколько разных областей
Unit-сценарии дают короткие объяснимые примеры: ноль, максимум, роль, событие и конкретный переход. Fuzz-функции расширяют входные величины при заранее заданной истории. Handler строит более длинные последовательности, но использует ограниченный набор номеров ради повторных обращений к существующим курсам.
Ограничение 1..20 находится в handler, а не в реестре. Положительное fuzz-свойство полного диапазона и граничный максимум остаются в обычном файле. Поэтому малая stateful-лаборатория не подменяет исходный договор допустимых идентификаторов.
Отрицательные случаи тоже имеют свои области. Читатель в handler конкретный, тогда как параметризованные свойства выбирают разные ненулевые чужие адреса с явно указанными исключениями окружения. Нулевые входы проверяются отдельно и не исчезают из-за преобразования данных внутри истории.
Готовим зависимости после чтения
Профиль проекта фиксирует Solidity 0.8.30, EVM cancun, Foundry 1.3.1 и forge-std 1.9.7. Архив содержит конфигурацию и remapping, но не установленную библиотеку. Читатель должен подготовить точную зависимость самостоятельно по официальному тегу, сохранив её происхождение.
Упоминание версии не доказывает совместимость установленного бинарного инструмента. Перед будущим исполнением нужно записать фактические значения окружения и сопоставить их с профилем. При осознанной миграции на новую версию отдельно проверяются API инструментов и параметры EVM; старый отчёт нельзя автоматически перенести.
Команды будущего запуска описаны в двадцать третьем и двадцать восьмом уроках. Сейчас они не выполнялись. Если читатель запустит лабораторию у себя, он получит фактическую обратную связь о синтаксисе, зависимостях, свойствах и ожидаемых результатах, которой наша текстовая подготовка пока не располагает.
Подключаем fork отдельно
Fork-файл находится в examples, чтобы отсутствие локального узла и параметров снимка не мешало основной подготовке. После собственного размещения его можно осознанно перенести в test; относительный импорт исходника остаётся подходящим для обеих папок.
Нужны сохранённый блок, адрес реестра, издатель, ожидаемый digest и доступный собственный RPC. В архиве нет придуманных значений, настоящего приватного ключа или production-адреса. Этот пример исследует копию известного состояния, а не выполняет размещение на публичной сети.
Для отчёта сохраняем также происхождение блока и конфигурации узла. Перезапущенный Anvil с тем же chain ID может иметь другую историю. Если fork не совпадает с ожиданием, сначала разбираем паспорт снимка, затем прикладные переходы.
Разделяем ожидание и свидетельство
| Часть работы | Статус комплекта |
|---|---|
| Требования и области свойств | Описаны |
| Исходники и последняя модель handler | Записаны |
| Компиляция и установка зависимостей | Не выполнялись |
| Unit, fuzz, invariant, fork | Не запускались |
| Покрытие и газ | Не измерены |
| Production-размещение | Не выполнялось |
После собственного запуска таблицу дополняют реальными выводами, seed, бюджетом и редакцией файлов. Отсутствие найденного нарушения означает результат выбранной конечной кампании. Оно не доказывает безопасность кошельков, RPC, индексатора, хранилища материалов и всех возможных историй приложения.
Если обнаружено нарушение, сохраняем минимальную последовательность и конкретное требование. Не меняем модель под ошибочный результат ради успешного статуса. Короткая регрессия остаётся рядом с генерацией, чтобы важная находка воспроизводилась независимо от случайного выбора следующих историй.
Дальше лабораторию можно связать с курсом браузерного интерфейса и курсом безопасности. Общий веб-манифест использует SHA-256 точных сохранённых байтов; Keccak-фикстуры в unit-сценариях остаются условными входами хранения. Полная программа доступна в оглавлении курса, исходники зависимости — в официальном forge-std 1.9.7.