Cadence テストフレームワークは、Cadence プログラムのテストを Cadence で記述する便利な方法を提供します。 この機能は、組み込みの`Test`スマートコントラクトによって提供されます。
Tip💡
テストフレームワークは、Flow CLI などのオフチェーンでのみ使用できます。
テストは、Cadence スクリプトの形式で記述する必要があります。 テストスクリプトには、test
プレフィックスで始まるテスト関数、テストの前に必ず実行されるsetup
関数、すべてのテストケースの最後に必ず実行されるtearDown
関数、各テストケースの前に実行されるbeforeEach
関数、各テストケースの後に実行されるafterEach
関数を含めることができます。 上記の 4 つの関数はすべてオプションです。
// `setup`関数はその他のテストケースの前に常に実行される。テスト全体で使われるようなものを初期化するために使うことができる。
access(all)
fun setup() {
}
// `beforeEach` 関数は各テストケースの前に実行されます。
access(all)
fun beforeEach() {
}
// `afterEach` 関数は各テストケースの後に実行されます。
access(all)
fun afterEach() {
}
// 「test」という接頭辞で始まるものが有効なテスト関数です。
access(all)
fun testSomething() {
}
access(all)
fun testAnotherThing() {
}
access(all)
fun testMoreThings() {
}
// テスト関数には、引数や戻り値を指定することはできません。
access(all)
fun testInvalidSignature(message: String): Bool {
}
// すべてのテストケースの最後に必ず実行される `tearDown` 関数。
access(all)
fun tearDown() {
}
Test Standard Library
テストフレームワークは、組み込みの Test
スマートコントラクトをインポートすることで使用できます。
import Test
Assertions
Test.assert
view fun assert(_ condition: Bool, message: String)
与えられた条件が偽の場合にテストケースを失敗させ、その理由を説明するメッセージを報告する。 message 引数はオプションである。
Test.fail
view fun fail(message: String)
テストケースを即座に失敗させ、その理由を説明するメッセージを表示します。
メッセージ引数はオプションです。
import Test
access(all)
fun testExample() {
let array = [1, 2, 3]
if array.length != 0 {
Test.fail(message: "Array length is not 0")
}
}
Test.expect
fun expect(_ value: AnyStruct, _ matcher: Matcher)
expect
関数は、値をマッチャー(matchersのセクション参照)に対してテストし、一致しない場合はテストに失敗します。
import Test
access(all)
fun testExample() {
let array = [1, 2, 3]
Test.expect(array.length, Test.equal(3))
}
Test.assertEqual
fun assertEqual(_ expected: AnyStruct, _ actual: AnyStruct)
assertEqual
関数は、与えられた値が等しくない場合にテストケースを失敗させ、2つの値がどのように異なるかを説明するメッセージを表示します。
import Test
access(all)
struct Foo {
access(all)
let answer: Int
init(answer: Int) {
self.answer = answer
}
}
access(all)
fun testExample() {
Test.assertEqual("this string", "this string")
Test.assertEqual(21, 21)
Test.assertEqual(true, true)
Test.assertEqual([1, 2, 3], [1, 2, 3])
Test.assertEqual(
{1: true, 2: false, 3: true},
{1: true, 2: false, 3: true}
)
let address1 = Address(0xf8d6e0586b0a20c7)
let address2 = Address(0xf8d6e0586b0a20c7)
Test.assertEqual(address1, address2)
let foo1 = Foo(answer: 42)
let foo2 = Foo(answer: 42)
Test.assertEqual(foo1, foo2)
let number1: Int64 = 100
let number2: UInt64 = 100
// Note that the two values need to have exactly the same type,
// and not just value, otherwise the assertion fails:
// assertion failed: not equal: expected: 100, actual: 100
Test.assertEqual(number1, number2)
}
Test.expectFailure
fun expectFailure(_ functionWrapper: ((): Void), errorMessageSubstring: String)
expectFailure
関数は、関数呼び出しをクロージャでラップし、指定したエラーメッセージ部分を含むエラーメッセージで失敗することを期待します。
import Test
access(all)
struct Foo {
access(self)
let answer: UInt8
init(answer: UInt8) {
self.answer = answer
}
access(all)
fun correctAnswer(_ input: UInt8): Bool {
if self.answer != input {
panic("wrong answer!")
}
return true
}
}
access(all)
fun testExample() {
let foo = Foo(answer: 42)
Test.expectFailure(fun(): Void {
foo.correctAnswer(43)
}, errorMessageSubstring: "wrong answer!")
}
`
Matchers
Matchersとは、テスト関数と関連ユーティリティ機能から構成されるオブジェクトです。access(all)
struct Matcher {
access(all)
let test: fun(AnyStruct): Bool
access(all)
init(test: fun(AnyStruct): Bool) {
self.test = test
}
/// Combine this matcher with the given matcher.
/// Returns a new matcher that succeeds if this and the given matcher succeed.
///
access(all)
fun and(_ other: Matcher): Matcher {
return Matcher(test: fun (value: AnyStruct): Bool {
return self.test(value) && other.test(value)
})
}
/// Combine this matcher with the given matcher.
/// Returns a new matcher that succeeds if this or the given matcher succeeds.
///
access(all)
fun or(_ other: Matcher): Matcher {
return Matcher(test: fun (value: AnyStruct): Bool {
return self.test(value) || other.test(value)
})
}
}
test
関数は値の評価基準を定義し、その値が関数で定義されたテスト基準に適合しているかどうかを示すブール値を返します。
and
およびor
関数を使用して、このマッチャーを別のマッチャーと組み合わせて、複数のテスト基準を持つ新しいマッチャーを作成することができます。and
メソッドは、このマッチャーと指定されたマッチャーの両方が成功した場合に成功する新しいマッチャーを返します。or
メソッドは、このマッチャーまたは指定されたマッチャーの少なくとも一方が成功した場合に成功する新しいマッチャーを返します。
汎用的な型を持つテスト関数を受け入れるマッチャーは、newMatcher
関数を使用して作成できます。
view fun newMatcher<T: AnyStruct>(_ test: fun(T): Bool): Test.Matcher
型パラメータT
はAnyStruct
型にバインドされます。これもオプションです。
例えば、与えられた整数値が負であるかどうかをチェックするマッチャーは、以下のように定義できます。
import Test
access(all)
fun testExample() {
let isNegative = Test.newMatcher(fun (_ value: Int): Bool {
return value < 0
})
Test.expect(-15, isNegative)
// Alternatively, we can use `Test.assert` and the matcher's `test` function.
Test.assert(isNegative.test(-15), message: "number is not negative")
}
access(all)
fun testCustomMatcherUntyped() {
let matcher = Test.newMatcher(fun (_ value: AnyStruct): Bool {
if !value.getType().isSubtype(of: Type<Int>()) {
return false
}
return (value as! Int) > 5
})
Test.expect(8, matcher)
}
access(all)
fun testCustomMatcherTyped() {
let matcher = Test.newMatcher<Int>(fun (_ value: Int): Bool {
return value == 7
})
Test.expect(7, matcher)
}
(他にもあります。詳しくは翻訳元の原文へ)
翻訳元->https://cadence-lang.org/docs/testing-framework
Previous << Measuring Time In Cadence
Flow BlockchainのCadence version1.0ドキュメント (Cadence Testing Framework)