Проверьте свои смарт-контракты с помощью Solidity и JavaScript

Предварительные требования: базовое понимание блокчейна, Ethereum и Javascript.

Полный рабочий код проекта можно найти на Github.

Важность тестирования программного обеспечения

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

Существует два основных типа тестирования программного обеспечения: модульные тесты и интеграционные тесты.

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

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

Блокчейн-тестирование

Пакет Truffle дает нам два пути для тестирования смарт-контрактов на надежность: тесты на надежность и тесты JavaScript. Вопрос в том, что мы должны использовать?

Ответ - оба.

Тесты на твердость

Написание тестов в Solidity дает нам возможность запускать тесты уровня Blockchain. Они позволяют тестам вызывать контракты и функции, как если бы они были в самой цепочке блоков. Чтобы проверить внутреннее поведение смарт-контрактов, мы можем:

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

Тесты JavaScript

Нам также необходимо убедиться, что смарт-контракты демонстрируют правильное внешнее поведение. Для тестирования смарт-контрактов извне Blockchain мы используем Web3js, как и наш DApp. Нам нужно быть уверенными, что наш интерфейс DApp будет правильно работать при вызове смарт-контрактов. Они подпадают под интеграционные тесты.

Пример проекта

Полный рабочий код проекта можно найти на Github

У нас есть два смарт-контракта: Background и EntryPoint.

Background - это внутренний контракт, с которым не взаимодействует наш интерфейс DApp. EntryPoint - это контракт, который предназначен для взаимодействия нашего DApp. Он ссылается на Background в своем коде.

Смарт-контракты

Выше мы видим наш Background контракт. Он предоставляет три функции: storeValue(uint), getValue(uint) и getNumberOfValues(). Все эти функции имеют простые инструкции, поэтому их легко протестировать.

Это наш EntryPoint контракт. Адрес нашего Background контракта вводится в конструктор и используется как переменная состояния с именем backgroundAddress. EntryPoint предоставляет три функции: getBackgroundAddress(), storeTwoValues(uint, uint) и getNumberOfValues().

storeTwoValues(uint, uint) вызывает функцию в Background контракте дважды, поэтому изолированное тестирование этой функции будет затруднительным. То же самое и с getNumberOfValues(). Это хорошие случаи для интеграционных тестов.

Твердость

В Solidity мы собираемся написать модульные тесты и интеграционные тесты для наших смарт-контрактов. Начнем с модульных тестов, поскольку они более простые.

Вот наш первый модульный тест: TestBackground:

Он проверяет наш Background contract, чтобы убедиться, что он:

  • Сохраняет новое значение в своем массиве values.
  • Возвращает значения по их индексу.
  • Хранит несколько значений в своем массиве values.
  • Возвращает размер своего values массива.

Это TestEntryPoint, с модульным тестом testItHasCorrectBackground() для нашего EntryPoint контракта:

Эта функция проверяет внедрение зависимостей. Как упоминалось ранее, другие функции в нашем EntryPoint контракте требуют взаимодействия с Background, поэтому мы не можем тестировать их изолированно.

Эти функции протестированы в наших интеграционных тестах:

Мы видим, что TestIntegrationEntryPoint использует расширение Background, называемое BackgroundTest, определенное в строке 43, чтобы действовать как наш фиктивный контракт. Это позволяет нашим тестам проверять, вызывает ли EntryPoint правильные функции в backgroundAddress контракте, на который он ссылается.

Тестовые файлы Javascript

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

Вот наш тест JavaScript, entryPoint.test.js:

Используя функции, доступные в нашем EntryPoint контракте, тесты JavaScript гарантируют, что значения извне Blockchain могут быть отправлены в смарт-контракт путем создания транзакций, нацеленных на функцию storeTwoValues(uint, uint) (строка 15). Получение количества значений, хранящихся в цепочке блоков, путем вызова getNumberOfValues() в строках 12 и 16 тестов гарантирует, что они будут сохранены.

Заключение

Когда дело доходит до тестирования смарт-контрактов, чем больше, тем лучше. Нельзя забывать и о том, что все возможные пути выполнения возвращают ожидаемые результаты. Используйте тесты Solidity на уровне Blockchain для модульных тестов и интеграционных тестов, а также используйте тесты Javascript для интеграционных тестов на уровне DApp.

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

Дальнейшее чтение

Если вы нашли этот учебник полезным, вы можете найти его полезными и для вашей разработки: