Пишем смарт-контракты на FunC - Урок 2 Тесты на FunC для первого смарт-контракта

Урок 2 Тесты на FunC для смарт-контракта

Введение

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

Требования

Для прохождения данного урока вам достаточно установить Node.js (желательно версии 18 или выше) и пройти первый урок.

Teсты для первого смарт-контракта

Для нашего первого смарт-контракта мы напишем следующие тесты:

  • вызовем recv_internal() с разными числами и проверим метод get_total
  • проверим вызов ошибки при не соответствии числа условию битности

Структура тестов в Blueprint

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

Сами тесты находятся в папке tests/. Для каждого смарт-контракта проекта (их может быть несколько) создаётся отдельный файл. В нашем случае в этой папке должен лежать лишь один файл Counter.spec.ts. В нём уже написано всё что нужно для тестирования нашего смарт-контракта, и даже прописан первый тест, который проверяет, что контракт успешно деплоится. Остаётся только добавить новые тесты.

Важный момент

Если запустить тесты командой npx blueprint test в текущем положении, вы увидите ошибку в единственном тесте, называющемся “should deploy”. В большинстве случаев, этот тест должен сразу выполняться успешно. Но наш контракт по-просту вызывает ошибку, потому что в полученном при деплое сообщении не лежит 32-битное число (в первом уроке мы специально добавили вызов такой ошибки при отсуствии числа).

Чтобы исправить это и игнорировать ошибку при деплое - найдите фрагмент кода, в котором проверяется успешность деплоя. Из него нужно убрать проверку на success. Должно получиться так:

expect(deployResult.transactions).toHaveTransaction({
    from: deployer.address,
    to: counter.address,
    deploy: true,
});

Теперь, если выполнить команду npx blueprint test в терминале вы увидите следующее:

 PASS  tests/Counter.spec.ts
  Counter
    ✓ should deploy (123 ms)

Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        1.085 s, estimated 2 s
Ran all test suites.
✨  Done in 2.47s.

Что означает успешное прохождение теста.

Тестируем вызов recv_internal() и get_total()

Напишем первый тест и разберем его код.

После стандартного теста it('should deploy', ...) напишем новый:

it('should update the number', async () => {
    // здесь будет код
});

Строка “should update the number” может быть любой. Это лишь пояснение для нас самих, в чём заключается суть теста.

Теперь напишем сам код теста:

it('should update the number', async () => {
    const caller = await blockchain.treasury('caller');

    await counter.sendNumber(caller.getSender(), toNano('0.01'), 10n);
    expect(await counter.getTotal()).toEqual(10n);

    await counter.sendNumber(caller.getSender(), toNano('0.01'), 5n);
    expect(await counter.getTotal()).toEqual(15n);

    await counter.sendNumber(caller.getSender(), toNano('0.01'), 1000n);
    expect(await counter.getTotal()).toEqual(1015n);
});

Разбираем

const caller = await blockchain.treasury('caller'); - здесь мы создаём новый Treasury, на котором в Sandbox уже лежит миллион монет для всех необходимых проверок. С него мы сможем отправлять сообщения контракту. По сути это просто кошелёк с балансом для тестов.

await counter.sendNumber(caller.getSender(), toNano('0.01'), 10n); - отправляем сообщение с числом 10, используя метод из обёртки, которую мы писали в первом уроке. В качестве отправителя используем caller, созданный выше.

expect(await counter.getTotal()).toEqual(10n); - проверяем (функция expect), что результат гет-метода getTotal() будет равен 10. Если это не так, то тест будет помечен как провалившийся и в терминале мы увидим где именно не прошла проверка. Если всё хорошо и результат совпадёт, то код просто будет исполняться дальше.

В следующих строках мы просто отправляем тому же контракту числа и сверяем результат getTotal(). После отправки 5 наша сумма должна уже равняться 15, а если отправить ещё 1000, то получится 1015. Если FunC код контракта написан правильно, тест должен быть помечен как пройденный.

Запустим тесты командой npx blueprint test, и если вы всё сделали без ошибок, получится следующий результат:

 PASS  tests/Counter.spec.ts
  Counter
    ✓ should deploy (126 ms)
    ✓ should update the number (79 ms)

Галочка означает, что наш новый тест успешно пройден.

Тестируем исключение

Напишем ещё один тест и разберем его код.

it('should throw error when number is not 32 bits', async () => {
    const caller = await blockchain.treasury('caller');

    const result = await counter.sendDeploy(caller.getSender(), toNano('0.01'));
    expect(result.transactions).toHaveTransaction({
        from: caller.address,
        to: counter.address,
        success: false,
        exitCode: 35,
    });
});

Разбираем

const caller = await blockchain.treasury('caller'); - здесь мы создаём новый Treasury, на котором в Sandbox уже лежит миллион монет для всех необходимых проверок. С него мы сможем отправлять сообщения контракту. По сути это просто кошелёк с балансом для тестов.

const result = await counter.sendDeploy(caller.getSender(), toNano('0.01')); - отправляем пустое сообщение без числа (именно такое использовалось для деплоя, поэтому для простоты мы и используем готовую функцию sendDeploy).

expect(result.transactions).toHaveTransaction({ ... }) - проверяем (функция expect), что среди транзакций, которые в результате вызова контракта обработались, будет транзакция с ошибкой 35.

Код ошибки 35 потому что именно это число мы прописали в смарт-контракте в функции throw_if

Запустим тесты командой npx blueprint test, и если вы всё сделали без ошибок, получится следующий результат:

 PASS  tests/Counter.spec.ts
  Counter
    ✓ should deploy (127 ms)
    ✓ should update the number (79 ms)
    ✓ should throw error when number is not 32 bits (53 ms)

Галочка означает, что наш новый тест успешно пройден.

На этом всё!

Вы прошли второй урок и успешно реализовали тесты для смарт-контракта.

P.S если есть какие-то вопросы, предлагаю задавать здесь

3 Likes

Очень интересно.Классная штука.