subgraphs > Developing > Creating > Birim Testi Framework'ü

Birim Testi Framework'ü

Reading time: 23 min

Learn how to use Matchstick, a unit testing framework developed by LimeChain. Matchstick enables subgraph developers to test their mapping logic in a sandboxed environment and sucessfully deploy their subgraphs.

Benefits of Using Matchstick

Bu bölüme bağlantı
  • It's written in Rust and optimized for high performance.
  • It gives you access to developer features, including the ability to mock contract calls, make assertions about the store state, monitor subgraph failures, check test performance, and many more.

Buradan Başlayın

Bu bölüme bağlantı

Install Dependencies

Bu bölüme bağlantı

In order to use the test helper methods and run tests, you need to install the following dependencies:

yarn add --dev matchstick-as

Install PostgreSQL

Bu bölüme bağlantı

graph-node depends on PostgreSQL, so if you don't already have it, then you will need to install it.

Note: It's highly recommended to use the commands below to avoid unexpected errors.

Installation command:

brew install postgresql

En son libpq.5.lib'e bir sembolik bağ oluşturun. Bu dizini önce oluşturmanız gerekebilir /usr/local/opt/postgresql/lib/

ln -sf /usr/local/opt/postgresql@14/lib/postgresql@14/libpq.5.dylib /usr/local/opt/postgresql/lib/libpq.5.dylib

Installation command (depends on your distro):

sudo apt install postgresql

Using WSL (Windows Subsystem for Linux)

Bu bölüme bağlantı

Matchstick'i WSL'de Docker yaklaşımı ve ikili yaklaşımı kullanarak kullanabilirsiniz. WSL biraz alengirli olabileceğinden, aşağıdaki gibi sorunlarla karşılaşırsanız birkaç ipucu verelim

static BYTES = Symbol("Bytes") SyntaxError: Unexpected token =

yada

<PROJECT_PATH>/node_modules/gluegun/build/index.js:13 throw up;

Lütfen daha yeni bir Node.js sürümünde olduğunuzdan emin olun. graph-cli artık v10.19.0'ı desteklemiyor ve bu sürüm, hala WSL'deki yeni Ubuntu görüntülerinin varsayılan sürümüdür. Örneğin, Matchstick'in v18.1.0 ile WSL'de çalıştığı doğrulandı, nvm aracılığıyla veya global Node.js'inizi güncelleyerek buna geçebilirsiniz. Nodejs'nizi güncelledikten sonra node_modules'ı silmeyi ve node_modules'u tekrar çalıştırmayı unutmayın! Daha sonra, libpq yüklü olduğundan emin olun, bunu çalıştırarak yapabilirsiniz

sudo apt-get install libpq-dev

Son olarak, graph test'i kullanmayın (global graph-cli yüklemenizi kullanmaktadır ve bazı nedenlerden dolayı şu anda WSL'de bozuk gibi görünüyor), bunun yerine yarn test veya npm run test kullanın (bu, proje düzeyindeki yerel graph-cli örneğini kullanacaktır, bu da harika çalışır). Bunun için tabiki package.json dosyanızda bir "test" script'i olması gerektiğini unutmayın, bunun gibi basit bir şey olabilir

{
"name": "demo-subgraph",
"version": "0.1.0",
"scripts": {
"test": "graph test",
...
},
"dependencies": {
"@graphprotocol/graph-cli": "^0.56.0",
"@graphprotocol/graph-ts": "^0.31.0",
"matchstick-as": "^0.6.0"
}
}

Using Matchstick

Bu bölüme bağlantı

Matchstick'i subgraph proje'nizde kullanmak için sadece bir terminal açın, proje'nizin kök(root) klasörüne gidin ve basitçe graph test [options] <datasource> - komutunu çalıştırın - bu en son Matchstick ikili dosyasını indirir ve belirtilen testi veya test klasöründeki tüm testleri çalıştırır (verikaynağı bayrağı belirtilmezse mevcut tüm testler).

CLI seçenekleri

Bu bölüme bağlantı

Bu, test klasöründeki tüm testleri çalıştıracaktır:

graph test

Bu, gravity.test.ts adında bir testi ve/veya gravity adında bir klasördeki tüm testleri çalıştıracaktır:

graph test gravity

Bu sadece belirtilen test dosyasını çalıştıracaktır:

graph test path/to/file.test.ts

Seçenekler:

-c, --coverage Testleri kapsama modunda çalıştırır
-d, --docker Testleri bir docker konteynerinde çalıştırır (Not: Subgraph kök klasöründen çalıştırın)
-f, --force İkili: İkilinin yeniden indirilmesini sağlar. Docker: Dockerfile'ın yeniden indirilmesi ve docker görüntüsünün yeniden oluşturulması.
-h, --help Kullanım bilgilerini gösterir
-l, --logs İşletim sistemi, CPU modeli ve indirme URL'si hakkında konsola günlük bilgilerini yazar (hata ayıklama amaçlıdır)
-r, --recompile Testlerin yeniden derlenmesini zorlar
-v, --version <tag> İndirmek/kullanmak istediğiniz rust ikilisinin sürümünü seçmenize yarar

graph-cli 0.25.2'den itibaren graph test -d bayrağı ile matchstick'i bir docker konteynerinde çalıştırmayı desteklemektedir. Docker uygulaması, bind mount kullandığından, graph test -d komutu her çalıştırıldığında docker görüntüsünü yeniden oluşturmak zorunda değildir. Alternatif olarak, matchstick deposundan docker'ı manuel olarak çalıştırmak için talimatları izleyebilirsiniz.

graph test -d, docker run'un -t bayrağıyla çalışmasını zorlar. Bu, etkileşimli olmayan ortamlar (örneğin, GitHub CI) içinde çalıştırmak için kaldırılmalıdır.

❗ Daha önce graph test çalıştırdıysanız, docker build sırasında aşağıdaki hatayla karşılaşabilirsiniz:

error from sender: failed to xattr node_modules/binary-install-raw/bin/binary-<platform>: permission denied

Bu durumda, kök klasör içinde bir .dockerignore dosyası oluşturun ve node_modules/binary-install-raw/bin'i ekleyin

Yapılandırma

Bu bölüme bağlantı

Matchstick, matchstick.yaml yapılandırma dosyası aracılığıyla özel testler, kütüphaneler ve manifest yolunu kullanacak şekilde yapılandırılabilir:

testsFolder: path/to/tests
libsFolder: path/to/libs
manifestPath: path/to/subgraph.yaml

Demo subgraph

Bu bölüme bağlantı

Demo Subgraph reposunu klonlayarak bu kılavuzdaki örnekleri deneyebilir ve ve istediğinizi yapabilirsiniz

Öğretici videolar

Bu bölüme bağlantı

Ayrıca, ""How to use Matchstick to write unit tests for your subgraphs"" konulu video serisine göz atabilirsiniz

Test yapısı

Bu bölüme bağlantı

ÖNEMLİ: Aşağıda açıklanan test yapısı matchstick-as sürümünün >=0.5.0 olmasını gerektirir

describe(name: String , () => {}) - Bir test grubunu tanımlar.

Notlar:

  • Açıklamalar zorunlu değildir. Hala test() fonksiyonunu describe() bloklarının dışında kullanabilirsiniz

Örnek:

import { describe, test } from "matchstick-as/assembly/index"
import { handleNewGravatar } from "../../src/gravity"
describe("handleNewGravatar()", () => {
test("Should create a new Gravatar entity", () => {
...
})
})

İç içe describe() örneği:

import { describe, test } from "matchstick-as/assembly/index"
import { handleUpdatedGravatar } from "../../src/gravity"
describe("handleUpdatedGravatar()", () => {
describe("When entity exists", () => {
test("updates the entity", () => {
...
})
})
describe("When entity does not exists", () => {
test("it creates a new entity", () => {
...
})
})
})

test(name: String, () =>, should_fail: bool) - Bir test durumu tanımlar. test() fonksiyonunu describe() blokları içinde veya bağımsız olarak kullanabilirsiniz.

Örnek:

import { describe, test } from "matchstick-as/assembly/index"
import { handleNewGravatar } from "../../src/gravity"
describe("handleNewGravatar()", () => {
test("Should create a new Entity", () => {
...
})
})

yada

test("handleNewGravatar() should create a new entity", () => {
...
})

Dosyadaki tüm testlerden önce bir kod bloğu çalıştırır. beforeAll, describe bloklarının içinde tanımlanırsa, o describe bloğunun başında çalışır.

Örnekler:

beforeAll içindeki kod, dosyadaki tüm testlerden önce bir kez çalıştırılacaktır.

import { describe, test, beforeAll } from "matchstick-as/assembly/index"
import { handleUpdatedGravatar, handleNewGravatar } from "../../src/gravity"
import { Gravatar } from "../../generated/schema"
beforeAll(() => {
let gravatar = new Gravatar("0x0")
gravatar.displayName = “First Gravatar”
gravatar.save()
...
})
describe("When the entity does not exist", () => {
test("it should create a new Gravatar with id 0x1", () => {
...
})
})
describe("When entity already exists", () => {
test("it should update the Gravatar with id 0x0", () => {
...
})
})

beforeAll içindeki kod, ilk describe bloğundaki tüm testlerden önce bir kez çalıştırılacaktır

import { describe, test, beforeAll } from "matchstick-as/assembly/index"
import { handleUpdatedGravatar, handleNewGravatar } from "../../src/gravity"
import { Gravatar } from "../../generated/schema"
describe("handleUpdatedGravatar()", () => {
beforeAll(() => {
let gravatar = new Gravatar("0x0")
gravatar.displayName = “First Gravatar”
gravatar.save()
...
})
test("updates Gravatar with id 0x0", () => {
...
})
test("creates new Gravatar with id 0x1", () => {
...
})
})

Dosyadaki tüm testlerden sonra bir kod bloğu çalıştırır. afterAll, describe bloklarının içinde tanımlanırsa, o describe bloğunun sonunda çalışır.

Örnek:

afterAll içindeki kod, dosyadaki tüm testlerden sonra bir kez çalıştırılacaktır.

import { describe, test, afterAll } from "matchstick-as/assembly/index"
import { handleUpdatedGravatar, handleNewGravatar } from "../../src/gravity"
import { store } from "@graphprotocol/graph-ts"
afterAll(() => {
store.remove("Gravatar", "0x0")
...
})
describe("handleNewGravatar, () => {
test("creates Gravatar with id 0x0", () => {
...
})
})
describe("handleUpdatedGravatar", () => {
test("updates Gravatar with id 0x0", () => {
...
})
})

afterAll içindeki kod, ilk describe bloğundaki tüm testlerden sonra bir kez çalıştırılacaktır

import { describe, test, afterAll, clearStore } from "matchstick-as/assembly/index"
import { handleUpdatedGravatar, handleNewGravatar } from "../../src/gravity"
describe("handleNewGravatar", () => {
afterAll(() => {
store.remove("Gravatar", "0x1")
...
})
test("It creates a new entity with Id 0x0", () => {
...
})
test("It creates a new entity with Id 0x1", () => {
...
})
})
describe("handleUpdatedGravatar", () => {
test("updates Gravatar with id 0x0", () => {
...
})
})

Her testten önce bir kod bloğu çalıştırır. beforeEach, describe bloklarının içinde tanımlanırsa, o describe bloğunun her testinden önce çalıştırılır.

Örnekler: beforeEach içindeki kod, her testten önce çalıştırılacaktır.

import { describe, test, beforeEach, clearStore } from "matchstick-as/assembly/index"
import { handleNewGravatars } from "./utils"
beforeEach(() => {
clearStore() // <-- clear the store before each test in the file
})
describe("handleNewGravatars, () => {
test("A test that requires a clean store", () => {
...
})
test("Second that requires a clean store", () => {
...
})
})
...

beforeEach içindeki kod, yalnızca o describe bloğundaki her testten önce çalıştırılacaktır

import { describe, test, beforeEach } from 'matchstick-as/assembly/index'
import { handleUpdatedGravatar, handleNewGravatar } from '../../src/gravity'
describe('handleUpdatedGravatars', () => {
beforeEach(() => {
let gravatar = new Gravatar('0x0')
gravatar.displayName = 'First Gravatar'
gravatar.imageUrl = ''
gravatar.save()
})
test('Upates the displayName', () => {
assert.fieldEquals('Gravatar', '0x0', 'displayName', 'First Gravatar')
// displayName'i 1. Gravatar olarak güncellemesi gereken kod
assert.fieldEquals('Gravatar', '0x0', 'displayName', '1st Gravatar')
store.remove('Gravatar', '0x0')
})
test('Updates the imageUrl', () => {
assert.fieldEquals('Gravatar', '0x0', 'imageUrl', '')
// imageUrl'yi https://www.gravatar.com/avatar/0x0 olarak değiştirmesi gereken kod
assert.fieldEquals('Gravatar', '0x0', 'imageUrl', 'https://www.gravatar.com/avatar/0x0')
store.remove('Gravatar', '0x0')
})
})

Her testten sonra bir kod bloğu çalıştırır. afterEach, describe bloklarının içinde tanımlanırsa, o describe bloğunun her testinden sonra çalıştırılır.

Örnekler:

afterEach içindeki kod, her testten sonra çalıştırılacaktır.

import { describe, test, beforeEach, afterEach } from "matchstick-as/assembly/index"
import { handleUpdatedGravatar, handleNewGravatar } from "../../src/gravity"
beforeEach(() => {
let gravatar = new Gravatar("0x0")
gravatar.displayName = “First Gravatar”
gravatar.save()
})
afterEach(() => {
store.remove("Gravatar", "0x0")
})
describe("handleNewGravatar", () => {
...
})
describe("handleUpdatedGravatar", () => {
test("Upates the displayName", () => {
assert.fieldEquals("Gravatar", "0x0", "displayName", "First Gravatar")
// displayName'i 1. Gravatar olarak güncellemesi gereken kod
assert.fieldEquals("Gravatar", "0x0", "displayName", "1st Gravatar")
})
test("Updates the imageUrl", () => {
assert.fieldEquals("Gravatar", "0x0", "imageUrl", "")
// imageUrl'yi https://www.gravatar.com/avatar/0x0 olarak değiştirmesi gereken kod
assert.fieldEquals("Gravatar", "0x0", "imageUrl", "https://www.gravatar.com/avatar/0x0")
})
})

afterEach içindeki kod, yalnızca o describe bloğundaki her testten sonra çalıştırılacaktır

import { describe, test, beforeEach, afterEach } from "matchstick-as/assembly/index"
import { handleUpdatedGravatar, handleNewGravatar } from "../../src/gravity"
describe("handleNewGravatar", () => {
...
})
describe("handleUpdatedGravatar", () => {
beforeEach(() => {
let gravatar = new Gravatar("0x0")
gravatar.displayName = "First Gravatar"
gravatar.imageUrl = ""
gravatar.save()
})
afterEach(() => {
store.remove("Gravatar", "0x0")
})
test("Upates the displayName", () => {
assert.fieldEquals("Gravatar", "0x0", "displayName", "First Gravatar")
// displayName'i 1. Gravatar olarak güncellemesi gereken kod
assert.fieldEquals("Gravatar", "0x0", "displayName", "1st Gravatar")
})
test("Updates the imageUrl", () => {
assert.fieldEquals("Gravatar", "0x0", "imageUrl", "")
// imageUrl'yi https://www.gravatar.com/avatar/0x0 olarak değiştirmesi gereken kod
assert.fieldEquals("Gravatar", "0x0", "imageUrl", "https://www.gravatar.com/avatar/0x0")
})
})

Açıklamalar

Bu bölüme bağlantı
fieldEquals(entityType: string, id: string, fieldName: string, expectedVal: string)
equals(expected: ethereum.Value, actual: ethereum.Value)
notInStore(entityType: string, id: string)
addressEquals(address1: Address, address2: Address)
bytesEquals(bytes1: Bytes, bytes2: Bytes)
i32Equals(number1: i32, number2: i32)
bigIntEquals(bigInt1: BigInt, bigInt2: BigInt)
booleanEquals(bool1: boolean, bool2: boolean)
stringEquals(string1: string, string2: string)
arrayEquals(array1: Array<ethereum.Value>, array2: Array<ethereum.Value>)
tupleEquals(tuple1: ethereum.Tuple, tuple2: ethereum.Tuple)
assertTrue(value: boolean)
assertNull<T>(value: T)
assertNotNull<T>(value: T)
entityCount(entityType: string, expectedCount: i32)

Sürüm 0.6.0 itibariyle, assert fonksiyonları özel hata mesajlarını da desteklemektedir

assert.fieldEquals('Gravatar', '0x123', 'id', '0x123', 'Id 0x123 olmalıdır')
assert.equals(ethereum.Value.fromI32(1), ethereum.Value.fromI32(1), 'Value 1'e eşit olmalıdır')
assert.notInStore('Gravatar', '0x124', 'Gravatar store'da olmamalıdır')
assert.addressEquals(Address.zero(), Address.zero(), 'Adres sıfır olmalıdır')
assert.bytesEquals(Bytes.fromUTF8('0x123'), Bytes.fromUTF8('0x123'), 'Byte değerleri eşit olmalıdır')
assert.i32Equals(2, 2, 'I32, 2'ye eşit olmalıdır')
assert.bigIntEquals(BigInt.fromI32(1), BigInt.fromI32(1), 'BigInt 1'e eşit olmalıdır')
assert.booleanEquals(true, true, 'Boolean true olmalıdır')
assert.stringEquals('1', '1', 'String 1'e eşit olmalıdır')
assert.arrayEquals([ethereum.Value.fromI32(1)], [ethereum.Value.fromI32(1)], 'Array'ler eşit olmalıdır')
assert.tupleEquals(
changetype<ethereum.Tuple>([ethereum.Value.fromI32(1)]),
changetype<ethereum.Tuple>([ethereum.Value.fromI32(1)]),
'Tuple'lar eşit olmalıdır',
)
assert.assertTrue(true, 'True olmalıdır')
assert.assertNull(null, 'Null olmalıdır')
assert.assertNotNull('not null', 'Null olmamalıdır')
assert.entityCount('Gravatar', 1, '2 gravatar olmalıdır')
assert.dataSourceCount('GraphTokenLockWallet', 1, 'GraphTokenLockWallet şablonunda bir veri kaynağı olmalıdır')
assert.dataSourceExists(
'GraphTokenLockWallet',
Address.zero().toHexString(),
'GraphTokenLockWallet sıfır adresi için bir veri kaynağına sahip olmalıdır',
)

Bir Birim Testi Yazın

Bu bölüme bağlantı

Demo Subgraph'taki Gravatar örneklerini kullanarak nasıl basit bir birim test görüneceğini görelim.

Aşağıdaki işleyici fonksiyonuna sahip olduğumuzu varsayarsak (iki yardımcı işlevle birlikte):

export function handleNewGravatar(event: NewGravatar): void {
let gravatar = new Gravatar(event.params.id.toHex())
gravatar.owner = event.params.owner
gravatar.displayName = event.params.displayName
gravatar.imageUrl = event.params.imageUrl
gravatar.save()
}
export function handleNewGravatars(events: NewGravatar[]): void {
events.forEach((event) => {
handleNewGravatar(event)
})
}
export function createNewGravatarEvent(
id: i32,
ownerAddress: string,
displayName: string,
imageUrl: string,
): NewGravatar {
let mockEvent = newMockEvent()
let newGravatarEvent = new NewGravatar(
mockEvent.address,
mockEvent.logIndex,
mockEvent.transactionLogIndex,
mockEvent.logType,
mockEvent.block,
mockEvent.transaction,
mockEvent.parameters,
)
newGravatarEvent.parameters = new Array()
let idParam = new ethereum.EventParam('id', ethereum.Value.fromI32(id))
let addressParam = new ethereum.EventParam(
'ownderAddress',
ethereum.Value.fromAddress(Address.fromString(ownerAddress)),
)
let displayNameParam = new ethereum.EventParam('displayName', ethereum.Value.fromString(displayName))
let imageUrlParam = new ethereum.EventParam('imageUrl', ethereum.Value.fromString(imageUrl))
newGravatarEvent.parameters.push(idParam)
newGravatarEvent.parameters.push(addressParam)
newGravatarEvent.parameters.push(displayNameParam)
newGravatarEvent.parameters.push(imageUrlParam)
return newGravatarEvent
}

Önce projemizde bir test dosyası oluşturmamız gerekiyor. Bunun nasıl görünebileceğine dair bir örnek:

import { clearStore, test, assert } from 'matchstick-as/assembly/index'
import { Gravatar } from '../../generated/schema'
import { NewGravatar } from '../../generated/Gravity/Gravity'
import { createNewGravatarEvent, handleNewGravatars } from '../mappings/gravity'
test('Can call mappings with custom events', () => {
// Bir test varlığı oluşturun ve bunu depoya başlangıç durumu olarak kaydedin (isteğe bağlı)
let gravatar = new Gravatar('gravatarId0')
gravatar.save()
// Mock etkinlikleri oluşturun
let newGravatarEvent = createNewGravatarEvent(12345, '0x89205A3A3b2A69De6Dbf7f01ED13B2108B2c43e7', 'cap', 'pac')
let anotherGravatarEvent = createNewGravatarEvent(3546, '0x89205A3A3b2A69De6Dbf7f01ED13B2108B2c43e7', 'cap', 'pac')
// Az önce oluşturduğumuz olayları geçiren çağrı eşleştirme fonksiyonları
handleNewGravatars([newGravatarEvent, anotherGravatarEvent])
// Deponun durumunu doğrulayın
assert.fieldEquals('Gravatar', 'gravatarId0', 'id', 'gravatarId0')
assert.fieldEquals('Gravatar', '12345', 'owner', '0x89205A3A3b2A69De6Dbf7f01ED13B2108B2c43e7')
assert.fieldEquals('Gravatar', '3546', 'displayName', 'cap')
// Bir sonraki testi temiz bir sayfa üzerinde başlatmak için depoyu boşaltın
clearStore()
})
test('Next test', () => {
//...
})

Analiz edilecek çok fazla şey var! Öncelikle fark etmemiz gereken önemli şey AssemblyScript yardımcı kütüphanemiz (npm modülü olarak dağıtılır) matchstick-as'den işleri içe aktardığımız. Repositoriyi burada bulabilirsiniz. matchstick-as bize yararlı test yöntemleri sağlar ve ayrıca test blokları oluşturmak için kullanacağımız test() işlevini tanımlar. Geri kalanı oldukça açık - şöyle olur:

  • İlk durumumuzu ayarlıyor ve bir özel Gravatar varlığı ekliyoruz;
  • createNewGravatarEvent() fonksiyonunu kullanarak verileriyle birlikte iki NewGravatarr olay nesnesini tanımlıyoruz;
  • handleNewGravatars() yöntemlerimizi bu olaylar için çağırıyoruz ve özel olay listemizi geçiyoruz;
  • Depo durumunu doğruluyoruz. Bu nasıl çalışır? - Bir varlık türü ve kimliğinin benzersiz bir kombinasyonunu geçiriyoruz. Ardından, bu varlıkta belirli bir alanı kontrol ediyoruz ve beklediğimiz değeri almasını sağlıyoruz. Hem depoya eklediğimiz ilk Gravatar Varlığı için hem de işleyici işlevi çağrıldığında eklenen iki Gravatar varlığı için bunu yapıyoruz;
  • Ve son olarak clearStore() kullanarak depoyu temizliyoruz, böylece bir sonraki testimiz temiz ve boş bir depo nesnesiyle başlayabilir. İstediğimiz kadar test bloğu tanımlayabiliriz.

İşte başardın - ilk testimizi oluşturduk! 👏

Şimdi testlerimizi çalıştırmak için subgraph kök klasörünüzde şunu çalıştırmanız yeterlidir:

graph test Gravity

Ve her şey yolunda giderse aşağıdakiyle karşılaşacaksınız:

Matchstick "Tüm testler geçildi!" diyor

Çok rastlanan test senaryoları

Bu bölüme bağlantı

Belirli bir durumla depoyu doldurma

Bu bölüme bağlantı

Kullanıcılar bilinen bir varlık kümesiyle depoyu doldurabilirler. Aşağıdaki örnek depoyu Gravatar varlığıyla başlatmak için kullanılabilir:

let gravatar = new Gravatar('entryId')
gravatar.save()

Olayla bir eşleştirme fonksiyonu çağırmak

Bu bölüme bağlantı

Kullanıcı, depoya bağlı bir eşleştirme fonksiyonuna özel bir olay oluşturabilir ve onu iletebilir:

import { store } from 'matchstick-as/assembly/store'
import { NewGravatar } from '../../generated/Gravity/Gravity'
import { handleNewGravatars, createNewGravatarEvent } from './mapping'
let newGravatarEvent = createNewGravatarEvent(12345, '0x89205A3A3b2A69De6Dbf7f01ED13B2108B2c43e7', 'cap', 'pac')
handleNewGravatar(newGravatarEvent)

Tüm eşitlemeleri olay fikstürleriyle çağırmak

Bu bölüme bağlantı

Kullanıcılar test fikstürleriyle eşleştirmeleri çağırabilirler.

import { NewGravatar } from '../../generated/Gravity/Gravity'
import { store } from 'matchstick-as/assembly/store'
import { handleNewGravatars, createNewGravatarEvent } from './mapping'
let newGravatarEvent = createNewGravatarEvent(12345, '0x89205A3A3b2A69De6Dbf7f01ED13B2108B2c43e7', 'cap', 'pac')
let anotherGravatarEvent = createNewGravatarEvent(3546, '0x89205A3A3b2A69De6Dbf7f01ED13B2108B2c43e7', 'cap', 'pac')
handleNewGravatars([newGravatarEvent, anotherGravatarEvent])
export function handleNewGravatars(events: NewGravatar[]): void {
events.forEach(event => {
handleNewGravatar(event);
});
}

Kontrat çağrılarını mocklama

Bu bölüme bağlantı

Kullanıcılar sözleşme çağrılarını mocklayabilir:

import { addMetadata, assert, createMockedFunction, clearStore, test } from 'matchstick-as/assembly/index'
import { Gravity } from '../../generated/Gravity/Gravity'
import { Address, BigInt, ethereum } from '@graphprotocol/graph-ts'
let contractAddress = Address.fromString('0x89205A3A3b2A69De6Dbf7f01ED13B2108B2c43e7')
let expectedResult = Address.fromString('0x90cBa2Bbb19ecc291A12066Fd8329D65FA1f1947')
let bigIntParam = BigInt.fromString('1234')
createMockedFunction(contractAddress, 'gravatarToOwner', 'gravatarToOwner(uint256):(address)')
.withArgs([ethereum.Value.fromSignedBigInt(bigIntParam)])
.returns([ethereum.Value.fromAddress(Address.fromString('0x90cBa2Bbb19ecc291A12066Fd8329D65FA1f1947'))])
let gravity = Gravity.bind(contractAddress)
let result = gravity.gravatarToOwner(bigIntParam)
assert.equals(ethereum.Value.fromAddress(expectedResult), ethereum.Value.fromAddress(result))

Gösterildiği gibi, bir sözleşme çağrısını mocklamak ve bir dönüş değeri sabitlemek için kullanıcı, bir sözleşme adresi, işlev adı, işlev imzası, bir argüman dizisi ve elbette dönüş değerini sağlamalıdır.

Kullanıcılar ayrıca fonksiyon geri çevirilerinide mocklayabilirler:

let contractAddress = Address.fromString('0x89205A3A3b2A69De6Dbf7f01ED13B2108B2c43e7')
createMockedFunction(contractAddress, 'getGravatar', 'getGravatar(address):(string,string)')
.withArgs([ethereum.Value.fromAddress(contractAddress)])
.reverts()

IPFS dosyalarını mocklama (Matchstick 0.4.1'den)

Bu bölüme bağlantı

Kullanıcılar mockIpfsFile(hash, filePath) fonksiyonunu kullanarak IPFS dosyalarını mocklama yeteneğine sahiptirler. Fonksiyon, ilk argümanı IPFS dosya hash/yol'u ve ikinci argümanı yerel bir dosyanın yolu olmak üzere iki argüman kabul eder.

NOT: ipfs.map/ipfs.mapJSON'u test ederken matchstck'in bunu algılaması için geri çağrıma işlevinin test dosyasından dışa aktarılması gerekiyor, örneğin aşağıdaki test örneğindeki processGravatar() fonksiyonu gibi:

.test.ts dosyası:

import { assert, test, mockIpfsFile } from 'matchstick-as/assembly/index'
import { ipfs } from '@graphprotocol/graph-ts'
import { gravatarFromIpfs } from './utils'
// Matchstck'in algılaması için ipfs.map() geri çağrısını dışa aktarın
export { processGravatar } from './utils'
test('ipfs.cat', () => {
mockIpfsFile('ipfsCatfileHash', 'tests/ipfs/cat.json')
assert.entityCount(GRAVATAR_ENTITY_TYPE, 0)
gravatarFromIpfs()
assert.entityCount(GRAVATAR_ENTITY_TYPE, 1)
assert.fieldEquals(GRAVATAR_ENTITY_TYPE, '1', 'imageUrl', 'https://i.ytimg.com/vi/MELP46s8Cic/maxresdefault.jpg')
clearStore()
})
test('ipfs.map', () => {
mockIpfsFile('ipfsMapfileHash', 'tests/ipfs/map.json')
assert.entityCount(GRAVATAR_ENTITY_TYPE, 0)
ipfs.map('ipfsMapfileHash', 'processGravatar', Value.fromString('Gravatar'), ['json'])
assert.entityCount(GRAVATAR_ENTITY_TYPE, 3)
assert.fieldEquals(GRAVATAR_ENTITY_TYPE, '1', 'displayName', 'Gravatar1')
assert.fieldEquals(GRAVATAR_ENTITY_TYPE, '2', 'displayName', 'Gravatar2')
assert.fieldEquals(GRAVATAR_ENTITY_TYPE, '3', 'displayName', 'Gravatar3')
})

utils.ts dosyası:

import { Address, ethereum, JSONValue, Value, ipfs, json, Bytes } from "@graphprotocol/graph-ts"
import { Gravatar } from "../../generated/schema"
...
// ipfs.map geri çağrısı
export function processGravatar(value: JSONValue, userData: Value): void {
// İşlem yapmayla ilgili ayrıntılar için JSONValue belgelerine bakın
// JSON değerleri ile
let obj = value.toObject()
let id = obj.get('id')
if (!id) {
return
}
// Geri çağrılar ayrıca varlıklar oluşturabilir
let gravatar = new Gravatar(id.toString())
gravatar.displayName = userData.toString() + id.toString()
gravatar.save()
}
// ipfs.cat'i çağıran fonksiyon
export function gravatarFromIpfs(): void {
let rawData = ipfs.cat("ipfsCatfileHash")
if (!rawData) {
return
}
let jsonData = json.fromBytes(rawData as Bytes).toObject()
let id = jsonData.get('id')
let url = jsonData.get("imageUrl")
if (!id || !url) {
return
}
let gravatar = new Gravatar(id.toString())
gravatar.imageUrl = url.toString()
gravatar.save()
}

Depo durumunu doğrulama

Bu bölüme bağlantı

Kullanıcılar, varlıkları doğrulayarak deponun nihai (veya orta) durumunu doğrulayabilirler. Bunun için, kullanıcı bir Varlık türü, bir Varlığın belirli bir kimliği, o Varlıktaki bir alanın adı ve alanın beklenen değerini sağlamalıdır. Hızlıca bir örneğe bakalım:

import { assert } from 'matchstick-as/assembly/index'
import { Gravatar } from '../generated/schema'
let gravatar = new Gravatar('gravatarId0')
gravatar.save()
assert.fieldEquals('Gravatar', 'gravatarId0', 'id', 'gravatarId0')

assert.fieldEquals () fonksiyonunu çalıştırmak, verilen alanın verilen beklenen değere karşı eşitliğini kontrol edecektir. Değerler eşit DEĞİLSE test başarısız olacak ve bir hata mesajı verecektir. Aksi takdirde, test başarılı bir şekilde geçecektir.

Olay üst verileriyle etkileşim

Bu bölüme bağlantı

Kullanıcılar newMockEvent() fonksiyonunu kullanarak ethereum.Event döndürebilen varsayılan işlem üst verilerini kullanabilir. Aşağıdaki örnek, Olay nesnesindeki bu alanlara nasıl okuma/yazma yapabileceğinizi gösterir:

// Okuma
let logType = newGravatarEvent.logType
// Yazma
let UPDATED_ADDRESS = '0xB16081F360e3847006dB660bae1c6d1b2e17eC2A'
newGravatarEvent.address = Address.fromString(UPDATED_ADDRESS)

Değişken eşitliğini doğrulama

Bu bölüme bağlantı
assert.equals(ethereum.Value.fromString("hello"); ethereum.Value.fromString("hello"));

Bir varlığın depoda olmadığını(not) doğrulama

Bu bölüme bağlantı

Kullanıcılar, bir varlığın depoda olmadığını doğrulayabilirler. Bu fonksiyon, bir varlık türü ve bir kimlik alır. Eğer varlık gerçekten depoda ise, test ilgili bir hata mesajı vererej başarısız olacaktır. Fonksiyonun nasıl kullanılacağına dair hızlıca bir örneğe bakalım:

assert.notInStore('Gravatar', '23')

Tüm mağazayı veya tüm mağazadan tek varlıkları yazdırma (hata ayıklama amaçlı)

Bu bölüme bağlantı

Bu yardımcı fonksiyon kullanılarak deponun tamamı konsola yazdırılabilir:

import { logStore } from 'matchstick-as/assembly/store'
logStore()

Sürüm 0.6.0 itibarıyla, logStore türetilmiş alanları yazdırmaz. Bunun yerine kullanıcılar yeni logEntity fonksiyonunu kullanabilir. Elbette ki logEntity, yalnızca türetilmiş alanlara sahip olanları değil, herhangi bir varlığı yazdırmak için kullanılabilir. logEntity, varlık türünü, varlık kimliğini ve ilgili türetilmiş varlıkları yazdırmak isteyip istemediğinizi belirten bir showRelated bayrağını alır.

import { logEntity } from 'matchstick-as/assembly/store'
logEntity("Gravatar", 23, true)

Beklenen başarısızlık

Bu bölüme bağlantı

Kullanıcılar, shouldFail bayrağını test() fonksiyonlarında kullanarak beklenen test başarısızlıklarına sahip olabilirler:

test(
'Should throw an error',
() => {
throw new Error()
},
true,
)

Test, shouldFail = true olarak işaretlenirse ama BAŞARISIZ olmazsa, bu kayıtlarda bir hata olarak görünecek ve test bloğu başarısız olacaktır. Ayrıca, with shouldFail = false (the default state) olarak işaretlenirse, test yürütücüsü çökecektir.

Birim testlerinde özel kayıt tutmanın eşitlemelerdeki kayıt tutmaktan tamamen aynıdır. Fark, günlük nesnesinin graph-ts yerine matchstick-as'dan içe aktarılması gerektmesidir. İşte tüm kritik olmayan kayıt türleriyle ilgili basit bir örnek:

import { test } from "matchstick-as/assembly/index";
import { log } from "matchstick-as/assembly/log";
test("Success", () => {
log.success("Success!". []);
});
test("Error", () => {
log.error("Error :( ", []);
});
test("Debug", () => {
log.debug("Debugging...", []);
});
test("Info", () => {
log.info("Info!", []);
});
test("Warning", () => {
log.warning("Warning!", []);
});

Kullanıcılar ayrıca şu şekilde kritik bir hatayı simüle edebilirler:

test('Blow everything up', () => {
log.critical('Boom!')
})

Kritik hataları kayıt altına almak, testlerin yürütülmesini durduracak ve her şeyi mahvedecektir. Sonuçta, kodunuzun dağıtımda kritik kayıtları içermediğinden emin olmak istiyoruz ve bunun olması durumunda hemen fark etmeniz gerekiyor.

Türetilmiş alanların test edilmesi

Bu bölüme bağlantı

Türetilmiş alanları test etme özelliği, belirli bir varlıkta bir alan belirleyip, bu varlıktan türetilmiş bir alan içeriyoren başka bir varlığın otomatik olarak güncellenmesini sağlayan bir özelliktir.

Sürüm 0.6.0 öncesinde, türetilmiş varlıklarıa varlık alanları/özellikleri olarak erişerek şu şekilde ulaşmak mümkündü:

let entity = ExampleEntity.load('id')
let derivedEntity = entity.derived_entity

Sürüm 0.6.0 itibarıyla bu işlem, graph-node’un loadRelated fonksiyonu kullanılarak yapılmaktadır. Türetilmiş varlıklara, işleyicilerdekiyle aynı şekilde erişilebilir.

test('Derived fields example test', () => {
let mainAccount = GraphAccount.load('12')!
assert.assertNull(mainAccount.get('nameSignalTransactions'))
assert.assertNull(mainAccount.get('operatorOf'))
let operatedAccount = GraphAccount.load('1')!
operatedAccount.operators = [mainAccount.id]
operatedAccount.save()
mockNameSignalTransaction('1234', mainAccount.id)
mockNameSignalTransaction('2', mainAccount.id)
mainAccount = GraphAccount.load('12')!
assert.assertNull(mainAccount.get('nameSignalTransactions'))
assert.assertNull(mainAccount.get('operatorOf'))
const nameSignalTransactions = mainAccount.nameSignalTransactions.load()
const operatorsOfMainAccount = mainAccount.operatorOf.load()
assert.i32Equals(2, nameSignalTransactions.length)
assert.i32Equals(1, operatorsOfMainAccount.length)
assert.stringEquals('1', operatorsOfMainAccount[0].id)
mockNameSignalTransaction('2345', mainAccount.id)
let nst = NameSignalTransaction.load('1234')!
nst.signer = '11'
nst.save()
store.remove('NameSignalTransaction', '2')
mainAccount = GraphAccount.load('12')!
assert.i32Equals(1, mainAccount.nameSignalTransactions.load().length)
})

loadInBlock'u Test Etme

Bu bölüme bağlantı

Sürüm 0.6.0 itibarıyla, kullanıcılar loadInBlock işlevini mockInBlockStore kullanarak test edebilir, bu sayede blok önbelleğindeki varlıkları simüle edebilirler.

import { afterAll, beforeAll, describe, mockInBlockStore, test } from 'matchstick-as'
import { Gravatar } from '../../generated/schema'
describe('loadInBlock', () => {
beforeAll(() => {
mockInBlockStore('Gravatar', 'gravatarId0', gravatar)
})
afterAll(() => {
clearInBlockStore()
})
test('entity.loadInBlock() metodunu kullanarak mevcut bloktaki önbellek depodan varlığı alabilir', () => {
let retrievedGravatar = Gravatar.loadInBlock('gravatarId0')
assert.stringEquals('gravatarId0', retrievedGravatar!.get('id')!.toString())
})
test('Varlık mevcut blokta yoksa entity.loadInBlock() çağrıldığında null döndürür', () => {
let retrievedGravatar = Gravatar.loadInBlock('IDoNotExist')
assert.assertNull(retrievedGravatar)
})
})

Dinamik Veri Kaynaklarının Test Edilmesi

Bu bölüme bağlantı

Dinamik veri kaynaklarının test edilmesi dataSource ad alanının context(), address() ve network() fonksiyonlarının geri dönüş değerlerinin mocklanmasıyla yapılabilir. Bu fonksiyonlar şu anda şunları döndürmektedir: context() - boş bir varlık döndürür (DataSourceContext), address() - 0x0000000000000000000000000000000000000000 döndürür, network() - mainnet döndürür. create(...) ve createWithContext(...) fonksiyonları hiçbir şey yapmamak için mocklanmıştır bu nedenle testlerde çağrılmaları gerekmez. Dönüş değerlerinde yapılacak değişiklikler matchstick-as'deki (version 0.3.0+)dataSourceMock ad alanının fonksiyonlarıyla yapılabilir.

Aşağıdaki örnekte:

Öncelikle aşağıdaki olay işleyicisine sahibiz (veri kaynağı mocklamasını göstermek için kasıtlı olarak amaç değişikliği):

export function handleApproveTokenDestinations(event: ApproveTokenDestinations): void {
let tokenLockWallet = TokenLockWallet.load(dataSource.address().toHexString())!
if (dataSource.network() == 'rinkeby') {
tokenLockWallet.tokenDestinationsApproved = true
}
let context = dataSource.context()
if (context.get('contextVal')!.toI32() > 0) {
tokenLockWallet.setBigInt('tokensReleased', BigInt.fromI32(context.get('contextVal')!.toI32()))
}
tokenLockWallet.save()
}

Ardından, dataSourceMock ad alanındaki yöntemlerden birini kullanarak tüm veri kaynağı fonksiyonları için yeni bir geri dönüş değeri ayarlayan testi görüyoruz:

import { assert, test, newMockEvent, dataSourceMock } from 'matchstick-as/assembly/index'
import { BigInt, DataSourceContext, Value } from '@graphprotocol/graph-ts'
import { handleApproveTokenDestinations } from '../../src/token-lock-wallet'
import { ApproveTokenDestinations } from '../../generated/templates/GraphTokenLockWallet/GraphTokenLockWallet'
import { TokenLockWallet } from '../../generated/schema'
test('Data source simple mocking example', () => {
let addressString = '0xA16081F360e3847006dB660bae1c6d1b2e17eC2A'
let address = Address.fromString(addressString)
let wallet = new TokenLockWallet(address.toHexString())
wallet.save()
let context = new DataSourceContext()
context.set('contextVal', Value.fromI32(325))
dataSourceMock.setReturnValues(addressString, 'rinkeby', context)
let event = changetype<ApproveTokenDestinations>(newMockEvent())
assert.assertTrue(!wallet.tokenDestinationsApproved)
handleApproveTokenDestinations(event)
wallet = TokenLockWallet.load(address.toHexString())!
assert.assertTrue(wallet.tokenDestinationsApproved)
assert.bigIntEquals(wallet.tokensReleased, BigInt.fromI32(325))
dataSourceMock.resetValues()
})

dataSourceMock.resetValues()'in en sonda çağrıldığına dikkat edin. Bunun nedeni değerler değiştirildiğinde hatırlanır ve varsayılan değerlere geri dönmek istiyorsanız sıfırlanmaları gerekir.

Dinamik veri kaynağı oluşturulmasının test edilmesi

Bu bölüme bağlantı

Sürüm 0.6.0 itibarıyla, yeni bir veri kaynağının bir şablonu temel alarak oluşturulup oluşturulmadığını test etmek mümkündür. Bu özellik hem ethereum/sözleşme hem de dosya/ipfs şablonlarını destekler. Bunun için dört fonksiyon bulunmaktadır:

  • assert.dataSourceCount(templateName, expectedCount) belirli bir şablondan beklenen veri kaynağı sayısını doğrulamak için kullanılabilir
  • assert.dataSourceExists(templateName, address/ipfsHash) belirli bir şablondan belirtilen kimliğe sahip (bu kimlik sözleşme adresi veya IPFS dosya hash’i olabilir) bir veri kaynağının oluşturulmuş olduğunu doğrular
  • logDataSources(templateName), belirtilen şablonda bulunan tüm veri kaynaklarını hata ayıklama amacıyla konsola yazdırır
  • readFile(path), bir IPFS dosyasını temsil eden JSON dosyasını okur ve içeriği Bytes olarak döndürür

ethereum/contract şablonlarının test edilmesi

Bu bölüme bağlantı
test('ethereum/sözleşme dataSource oluşturma örneği', () => {
// GraphTokenLockWallet şablonundan oluşturulmuş veri kaynağı olmadığını doğrula
assert.dataSourceCount('GraphTokenLockWallet', 0)
// 0xA16081F360e3847006dB660bae1c6d1b2e17eC2A adresiyle yeni bir GraphTokenLockWallet veri kaynağı oluştur
GraphTokenLockWallet.create(Address.fromString('0xA16081F360e3847006dB660bae1c6d1b2e17eC2A'))
// datSource oluşturulduğunu doğrula
assert.dataSourceCount('GraphTokenLockWallet', 1)
// İkinci dataSource'u bağlamıyla ekle
let context = new DataSourceContext()
context.set('contextVal', Value.fromI32(325))
GraphTokenLockWallet.createWithContext(Address.fromString('0xA16081F360e3847006dB660bae1c6d1b2e17eC2B'), context)
// Şimdi 2 veri kaynağı olduğunu doğrula
assert.dataSourceCount('GraphTokenLockWallet', 2)
// "0xA16081F360e3847006dB660bae1c6d1b2e17eC2B" adresine sahip bir veri kaynağının oluşturulduğunu doğrula
// `Address` türü çözümlendiğinde küçük harfe dönüştürüldüğünden, doğrulama yaparken adresi tamamen küçük harf olarak geçmelisiniz
assert.dataSourceExists('GraphTokenLockWallet', '0xA16081F360e3847006dB660bae1c6d1b2e17eC2B'.toLowerCase())
logDataSources('GraphTokenLockWallet')
})
logDataSource çıktısı örneği
Bu bölüme bağlantı
🛠 {
"0xa16081f360e3847006db660bae1c6d1b2e17ec2a": {
"kind": "ethereum/contract",
"name": "GraphTokenLockWallet",
"address": "0xa16081f360e3847006db660bae1c6d1b2e17ec2a",
"context": null
},
"0xa16081f360e3847006db660bae1c6d1b2e17ec2b": {
"kind": "ethereum/contract",
"name": "GraphTokenLockWallet",
"address": "0xa16081f360e3847006db660bae1c6d1b2e17ec2b",
"context": {
"contextVal": {
"type": "Int",
"data": 325
}
}
}
}

dosya/ipfs şemalarını test etme

Bu bölüme bağlantı

Akıllı sözleşme dinamik veri kaynaklarına benzer şekilde kullanıcılar, test dosyası veri kaynaklarını ve bunların işleyicilerini test edebilirler

subgraph.yaml örneği
Bu bölüme bağlantı
...
templates:
- kind: file/ipfs
name: GraphTokenLockMetadata
network: mainnet
mapping:
kind: ethereum/events
apiVersion: 0.0.6
language: wasm/assemblyscript
file: ./src/token-lock-wallet.ts
handler: handleMetadata
entities:
- TokenLockMetadata
abis:
- name: GraphTokenLockWallet
file: ./abis/GraphTokenLockWallet.json
schema.graphql örneği
Bu bölüme bağlantı
"""
Kilitli GRT tutan Token Kilit Cüzdanları
"""
type TokenLockMetadata @entity {
"Token kilit cüzdanının adresi"
id: ID!
"Serbest bırakma programının başlangıç zamanı"
startTime: BigInt!
"Serbest bırakma programının bitiş zamanı"
endTime: BigInt!
"Başlangıç zamanı ile bitiş zamanı arasındaki periyot sayısı"
periods: BigInt!
"Serbest bırakmaların başladığı zaman"
releaseStartTime: BigInt!
}
metadata.json örneği
Bu bölüme bağlantı
{
"startTime": 1,
"endTime": 1,
"periods": 1,
"releaseStartTime": 1
}
İşleyici örneği
Bu bölüme bağlantı
export function handleMetadata(content: Bytes): void {
// dataSource.stringParams() File Veri Kaynağı CID'sini döndürür
// stringParam() işleyici testinde taklit edilecektir
// daha fazla bilgi için https://thegraph.com/docs/en/developing/creating-a-subgraph/#create-a-new-handler-to-process-files
process - files
let tokenMetadata = new TokenLockMetadata(dataSource.stringParam())
const value = json.fromBytes(content).toObject()
if (value) {
const startTime = value.get('startTime')
const endTime = value.get('endTime')
const periods = value.get('periods')
const releaseStartTime = value.get('releaseStartTime')
if (startTime && endTime && periods && releaseStartTime) {
tokenMetadata.startTime = startTime.toBigInt()
tokenMetadata.endTime = endTime.toBigInt()
tokenMetadata.periods = periods.toBigInt()
tokenMetadata.releaseStartTime = releaseStartTime.toBigInt()
}
tokenMetadata.save()
}
}
Test örneği
Bu bölüme bağlantı
import { assert, test, dataSourceMock, readFile } from 'matchstick-as'
import { Address, BigInt, Bytes, DataSourceContext, ipfs, json, store, Value } from '@graphprotocol/graph-ts'
import { handleMetadata } from '../../src/token-lock-wallet'
import { TokenLockMetadata } from '../../generated/schema'
import { GraphTokenLockMetadata } from '../../generated/templates'
test('dosya/ipfs veri kaynağı oluşturma örneği', () => {
// ipfsHash + ipfs dosya yolu kullanılarak veri kaynağı CID'si oluşturulur
// Örneğin QmaXzZhcYnsisuue5WRdQDH6FDvqkLQX1NckLqBYeYYEfm/example.json
const ipfshash = 'QmaXzZhcYnsisuue5WRdQDH6FDvqkLQX1NckLqBYeYYEfm'
const CID = `${ipfshash}/example.json`
// Oluşturulan CID kullanılarak yeni bir dataSource oluşturulur
GraphTokenLockMetadata.create(CID)
// dataSource oluşturulduğunu doğrula
assert.dataSourceCount('GraphTokenLockMetadata', 1)
assert.dataSourceExists('GraphTokenLockMetadata', CID)
logDataSources('GraphTokenLockMetadata')
// Şimdi dataSource metadatasını ve spesifik olarak dataSource.stringParam()'ı taklit etmemiz gerekiyor
// dataSource.stringParams aslında dataSource.address() değerini kullanır, bu yüzden matchstick-as kütüphanesinden aldığımız dataSourceMock ile adresi taklit edeceğiz
// İlk olarak değerleri sıfırlayıp ardından dataSourceMock.setAddress() ile CID'yi atayacağız
dataSourceMock.resetValues()
dataSourceMock.setAddress(CID)
// Şimdi dataSource işleyicisine geçirmek için Bytes oluşturmalıyız
// Bunun yerel bir json dosyasını okuyan ve içeriğini Bytes olarak döndüren readFile fonksiyonunu kullanıyoruz
const content = readFile(`path/to/metadata.json`)
handleMetadata(content)
// Şimdi bir TokenLockMetadata'nın oluşturulup oluşturulmadığını test edeceğiz
const metadata = TokenLockMetadata.load(CID)
assert.bigIntEquals(metadata!.endTime, BigInt.fromI32(1))
assert.bigIntEquals(metadata!.periods, BigInt.fromI32(1))
assert.bigIntEquals(metadata!.releaseStartTime, BigInt.fromI32(1))
assert.bigIntEquals(metadata!.startTime, BigInt.fromI32(1))
})

Test Kapsamı

Bu bölüme bağlantı

Subgraph geliştiricileri Matchstick'i kullanarak, yazılan birim testlerinin test kapsamını hesaplayacak bir komut dosyası çalıştırabilirler.

Test kapsama aracı derlenmiş test wasm ikililerini alır ve bunları daha sonra subgraph.yaml dosyasında tanımlanan işlevlerin çağrılıp çağrılmadığını görmek için kolayca incelenebilen wat dosyalarına dönüştürür. Kod kapsamı (ve bir bütün olarak test) AssemblyScript ve WebAssembly'de çok erken aşamalarda olduğundan, Matchstick dallanma kapsamını kontrol edemez. Bunun yerine, belirli bir işleyici çağrılmışsa, bunun için olay/fonksiyonun uygun şekilde taklit edildiği savına güveniyoruz.

Ön Koşullar

Bu bölüme bağlantı

Matchstick tarafından sağlanan test kapsama fonksiyonlarını çalıştırmak için önceden hazırlamanız gereken birkaç şey bulunmaktadır:

İşleyicilerinizi dışa aktarın

Bu bölüme bağlantı

Matchstick'in hangi işleyicilerin çalıştığını kontrol etmesi için, bu işleyicilerin test file'dan dışa aktarılması gerekir. Mesela, bizim örneğimizde gravity.test.ts dosyamızda aşağıdaki işleyici içe aktarılır:

import { handleNewGravatar } from '../../src/gravity'

Bu fonksiyonun görünür olması için (adıyla wat dosyasına dahil edilmesi için) ayrıca onuda şöyle dışa aktarmamız gerekmektedir:

export { handleNewGravatar }

Her şey hazır olduğunda, test kapsama aracını çalıştırmak için basitçe şunu çalıştırın:

graph test -- -c

Ayrıca package.json dosyanıza şu şekilde özel bir kapsama(coverage) komutu ekleyebilirsiniz:

"scripts": {
/.../
"coverage": "graph test -- -c"
},

Bu, kapsama aracını çalıştıracak ve terminalde buna benzer bir şey göreceksiniz:

$ graph test -c
Skipping download/install step because binary already exists at /Users/petko/work/demo-subgraph/node_modules/binary-install-raw/bin/0.4.0
___ ___ _ _ _ _ _
| \/ | | | | | | | (_) | |
| . . | __ _| |_ ___| |__ ___| |_ _ ___| | __
| |\/| |/ _` | __/ __| '_ \/ __| __| |/ __| |/ /
| | | | (_| | || (__| | | \__ \ |_| | (__| <
\_| |_/\__,_|\__\___|_| |_|___/\__|_|\___|_|\_\
Compiling...
Running in coverage report mode.
Reading generated test modules... 🔎️
Generating coverage report 📝
Handlers for source 'Gravity':
Handler 'handleNewGravatar' is tested.
Handler 'handleUpdatedGravatar' is not tested.
Handler 'handleCreateGravatar' is tested.
Test coverage: 66.7% (2/3 handlers).
Handlers for source 'GraphTokenLockWallet':
Handler 'handleTokensReleased' is not tested.
Handler 'handleTokensWithdrawn' is not tested.
Handler 'handleTokensRevoked' is not tested.
Handler 'handleManagerUpdated' is not tested.
Handler 'handleApproveTokenDestinations' is not tested.
Handler 'handleRevokeTokenDestinations' is not tested.
Test coverage: 0.0% (0/6 handlers).
Global test coverage: 22.2% (2/9 handlers).

Tutulan kayıt çıktısında test çalışma süresi

Bu bölüme bağlantı

Tutulan kayıt çıktısı test çalışma süresini içerir. İşte buna bir örnek:

[Thu, 31 Mar 2022 13:54:54 +0300] Program executed in: 42.270ms.

Çok rastlanan derleyici hataları

Bu bölüme bağlantı

Critical: Could not create WasmInstance from valid module with context: unknown import: wasi_snapshot_preview1::fd_write has not been defined

Bu hata kodunuzda console.log kullandığınız anlamına gelir. Bu komut AssemblyScript tarafından desteklenmez. Lütfen Logging API'yi kullanmayı düşünün.

ERROR TS2554: Expected ? arguments, but got ?.

return new ethereum.Block(defaultAddressBytes, defaultAddressBytes, defaultAddressBytes, defaultAddress, defaultAddressBytes, defaultAddressBytes, defaultAddressBytes, defaultBigInt, defaultBigInt, defaultBigInt, defaultBigInt, defaultBigInt, defaultBigInt, defaultBigInt, defaultBigInt);

in ~lib/matchstick-as/assembly/defaults.ts(18,12)

ERROR TS2554: Expected ? arguments, but got ?.

return new ethereum.Transaction(defaultAddressBytes, defaultBigInt, defaultAddress, defaultAddress, defaultBigInt, defaultBigInt, defaultBigInt, defaultAddressBytes, defaultBigInt);

in ~lib/matchstick-as/assembly/defaults.ts(24,12)

Argümanlardaki uyumsuzluk, graph-ts ve matchstick-as arasındaki uyumsuzluktan kaynaklanır. Bu gibi sorunları düzeltmenin en iyi yolu her şeyi en son yayınlanan sürüme güncellemektir.

For any additional support, check out this demo subgraph repo using Matchstick.

Soru, geri bildirim, özellik istekleri veya sadece iletişim kurmak istiyorsanız en iyi yer Matchstick için ayrılmış bir kanal olan 🔥| unit-testing kanalına sahip olduğumuz The Graph Discord'udur.

Sayfayı Düzenle

Önceki
Genel AssemblyScript Sorunları
Sonraki
Subgraph Studio Kullanarak Dağıtma
Sayfayı Düzenle