TGStat
TGStat
Введите текст для поиска
Расширенный поиск каналов
  • flag Russian
    Язык сайта
    flag Russian flag English flag Uzbek
  • Вход на сайт
  • Каталог
    Каталог каналов и чатов Региональные подборки Тематические подборки Платные каналы Поиск каналов
    Добавить канал/чат
  • Рейтинги
    Рейтинг каналов Рейтинг чатов Рейтинг публикаций
    Рейтинги брендов и персон
  • Аналитика
  • Поиск по публикациям
  • Мониторинг Telegram
  • Продвижение
    Реклама через Яндекс Бизнес Реклама в каналах через TGStat Agency Реклама на сайте TGStat.ru
Из Solidity в AI и дальше

1 Nov 2023, 11:58

Открыть в Telegram Поделиться Пожаловаться

Foundry с 0. Часть 13

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

Для начала добавим новую функцию в наш контракт Counter.sol:

function setNumber100(uint256 newNumber) public {
require(newNumber == 100, 'Wrong numer!');
number = newNumber;
}

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

Как это протестировать?

Если мы просто хотим убедиться, что данная функция не сработает, если число будет отличное от 100, то можно сделать так:

function testFail_setNumber100() public {
counter.setNumber100(150);
}

Обратите внимание на testFail. Так мы говорим Foundry, что ожидаем откат транзакции. Другими словами, если сейчас транзакция не пройдет, то результатом будет fail и таким образом тест удастся. Поняли, в чем дело?

Когда мы пишем testFail, необходимо чтобы транзакция упала - тогда тест пройдет. Если же транзакция завершится нормально, то тест будет "завален". Тут, скажем, немного обратная от привычной логика.

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

Как протестировать require и условия с кастомными ошибками?

В Foundry есть так называемые читкоды, которые сильно облегчаю работу с тестами и взаимодействие с локальным блокчейном. Вместе с библиотекой Test мы можем использовать огромное количество читов.

Одним из них является:

vm.expectRevert();

Тут мы как бы обращаемся к vm (virtual machine) и говорим, что ожидаем реверт с некоторым сообщением. Наш тест может выглядеть так:

function test_setNumber_Revert() public {
vm.expectRevert("Wrong numer!");
counter.setNumber100(150);
}

Обратите внимание, что читкод мы пишем до исполнения функции, а не после нее. Это очень важно для хода выполнения тестов! Более того, в этом случае мы пишем название теста просто test_testName, а не testFail_testName, т.е. слово fail тут уже не нужно.

Далее посмотрим на два вида кастомных ошибок.

Для начала добавим их и две новые функции в контракт:

error WrongNum(address caller, uint256 num);
error WrongSet();

function setNumber150(uint256 newNumber) public {
if (newNumber != 150) revert WrongSet();
number = newNumber;
}

function setNumber200(uint256 newNumber) public {
if (newNumber != 200) revert WrongNum(msg.sender, newNumber);
number = newNumber;
}

Тесты для обеих функций могут выглядеть так:

function test_setNumber_Revert150() public {
vm.expectRevert(abi.encodeWithSignature('WrongSet()'));
counter.setNumber150(200);
}

function test_setNumber_Revert200() public {
vm.expectRevert(abi.encodeWithSignature("WrongNum(address,uint256)", address(this),150));
counter.setNumber200(150);
}

Ошибки и их аргументы мы оборачиваем в abi.encodeWithSignature() и это становится нашим ожидаемым результатом тестов.

Я видел в нескольких видео, а также в официальной документации, что порой для кастомных ошибок можно использовать более простые конструкции, типа:

function test_setNumber_Revert150() public {
vm.expectRevert('WrongSet.selector);
counter.setNumber150(200);
}

Оба варианта рабочие. Можете смело использовать их в своих тестах.

Еще интереснее дела обстоят с порождением событий и их тестированием.

Объявим его в нашем контракте Counter:

event NewEvent(uint256 num);

и добавим запись в функцию increment() в виде:

emit NewEvent(number);

Наш тест для событий может выглядеть так:

function test_IncrementEvent() public {
vm.expectEmit(true, true, true, false);
emit NewEvent(counter.number());
counter.increment();
}

Сначала мы используем новый читкод vm.expectEmit(), который принимает четыре аргумента в качестве булевых значение. Первые три устанавливаются для отслеживания indexed параметров в событии, последний - нужна ли проверка входных значений.

Далее нам нужно породить это событие в нашем тесте и уже после вызвать функцию.

Немного странно, но так это работает.

426 0 0 6 1
Каталог
Каталог каналов и чатов Подборки каналов Поиск каналов Добавить канал/чат
Рейтинги
Рейтинг каналов Telegram Рейтинг чатов Telegram Рейтинг публикаций Рейтинги брендов и персон
API
API статистики API поиска публикаций API Callback
Наши каналы
@TGStat @TGStat_Chat @telepulse @TGStatAPI
Почитать
Академия TGStat Исследование Telegram 2019 Исследование Telegram 2021 Исследование Telegram 2023
Контакты
Справочный центр Поддержка Почта Вакансии
Всякая всячина
Пользовательское соглашение Политика конфиденциальности Публичная оферта
Наши боты
@TGStat_Bot @SearcheeBot @TGAlertsBot @tg_analytics_bot @TGStatChatBot