title |
---|
युनिट चाचणी फ्रेमवर्क |
मॅचस्टिक हे एक युनिट चाचणी फ्रेमवर्क आहे, जे LimeChain ने विकसित केले आहे, जे सबग्राफ डेव्हलपरना त्यांच्या मॅपिंग लॉजिकची सँडबॉक्स्ड वातावरणात चाचणी घेण्यास आणि त्यांचे सबग्राफ आत्मविश्वासाने तैनात करण्यास सक्षम करते!
चाचणी मदतनीस पद्धती वापरण्यासाठी आणि चाचण्या चालवण्यासाठी, तुम्हाला खालील अवलंबन स्थापित करणे आवश्यक आहे:
yarn add --dev matchstick-as
❗ ग्राफ-नोड
PostgreSQL वर अवलंबून आहे, त्यामुळे तुमच्याकडे ते आधीपासून नसेल, तर तुम्हाला ते इंस्टॉल करावे लागेल. आम्ही खालील आदेश वापरण्याचा सल्ला देतो कारण ते इतर कोणत्याही प्रकारे जोडल्यास अनपेक्षित त्रुटी येऊ शकतात!
Postgres स्थापना आदेश:
brew install postgresql
नवीनतम libpq.5.lib साठी एक सिमलिंक तयार करा तुम्हाला प्रथम हे dir तयार करावे लागेल /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
पोस्टग्रेस इंस्टॉलेशन कमांड (तुमच्या डिस्ट्रोवर अवलंबून आहे):
sudo apt install postgresql
डॉकर दृष्टिकोन आणि बायनरी दृष्टिकोन वापरून तुम्ही WSL वर मॅचस्टिक वापरू शकता. डब्ल्यूएसएल थोडे अवघड असू शकते, यासारख्या समस्या आल्यास येथे काही टिपा आहेत
static BYTES = Symbol("Bytes") SyntaxError: Unexpected token =
किंवा
<PROJECT_PATH>/node_modules/gluegun/build/index.js:13 throw up;
कृपया खात्री करा की तुम्ही Node.js graph-cli च्या नवीन आवृत्तीवर आहात आता v10.19.0 ला सपोर्ट करत नाही आणि WSL वरील नवीन Ubuntu प्रतिमांसाठी ती डीफॉल्ट आवृत्ती आहे. उदाहरणार्थ मॅचस्टिक v18.1.0 सह WSL वर काम करत असल्याची पुष्टी झाली आहे, तुम्ही त्यावर nvm द्वारे किंवा तुम्ही तुमचे ग्लोबल Node.js अपडेट केल्यास त्यावर स्विच करू शकता. तुम्हाला नोडज अपडेट केल्यानंतर node_modules
हटवायला आणि npm install
पुन्हा चालवायला विसरू नका! त्यानंतर, तुमच्याकडे libpq स्थापित असल्याची खात्री करा, तुम्ही ते चालवून करू शकता
sudo apt-get install libpq-dev
आणि शेवटी, ग्राफ चाचणी
वापरू नका (जे तुमचे ग्राफ-क्लीचे जागतिक इंस्टॉलेशन वापरते आणि काही कारणास्तव ते सध्या WSL वर तुटलेले दिसते), त्याऐवजी यार्न टेस्ट
वापरा. किंवा npm रन चाचणी
(जे ग्राफ-क्लीचे स्थानिक, प्रकल्प-स्तरीय उदाहरण वापरेल, जे मोहिनीसारखे कार्य करते). त्यासाठी तुम्हाला तुमच्या package.json
फाईलमध्ये अर्थातच एक "test"
स्क्रिप्ट असणे आवश्यक आहे जे सोपे असू शकते
{
"name": "demo-subgraph",
"version": "0.1.0",
"scripts": {
"test": "graph test",
...
},
"dependencies": {
"@graphprotocol/graph-cli": "^0.30.0",
"@graphprotocol/graph-ts": "^0.27.0",
"matchstick-as": "^0.5.0"
}
}
तुमच्या सबग्राफ प्रोजेक्टमध्ये Matchstick वापरण्यासाठी फक्त एक टर्मिनल उघडा, तुमच्या प्रोजेक्टच्या रूट फोल्डरवर नेव्हिगेट करा आणि फक्त ग्राफ चाचणी [options] <datasource>
- ते नवीनतम Matchstick बायनरी डाउनलोड करते आणि चाचणी फोल्डरमध्ये निर्दिष्ट चाचणी किंवा सर्व चाचण्या चालवते (किंवा कोणताही डेटासोर्स ध्वज निर्दिष्ट केलेला नसल्यास सर्व विद्यमान चाचण्या).
हे चाचणी फोल्डरमधील सर्व चाचण्या चालवेल:
आलेख चाचणी
हे gravity.test.ts नावाची चाचणी आणि/किंवा गुरुत्वाकर्षण नावाच्या फोल्डरच्या आत सर्व चाचणी चालवेल:
graph test gravity
हे फक्त विशिष्ट चाचणी फाइल चालवेल:
graph test path/to/file.test.ts
पर्याय:
-c, --coverage Run the tests in coverage mode
-d, --docker Run the tests in a docker container (Note: Please execute from the root folder of the subgraph)
-f, --force Binary: Redownloads the binary. Docker: Redownloads the Dockerfile and rebuilds the docker image.
-h, --help Show usage information
-l, --logs Logs to the console information about the OS, CPU model and download url (debugging purposes)
-r, --recompile Forces tests to be recompiled
-v, --version <tag> Choose the version of the rust binary that you want to be downloaded/used
graph-cli 0.25.2
वरून, ग्राफ चाचणी
कमांड -d
सह डॉकर कंटेनरमध्ये matchstick
चालवण्यास समर्थन देते > ध्वज. डॉकर अंमलबजावणी बाइंड माउंट वापरते त्यामुळे प्रत्येक वेळी ग्राफवर डॉकर प्रतिमा पुन्हा तयार करावी लागत नाही test -d
कमांड कार्यान्वित केली आहे. वैकल्पिकरित्या तुम्ही डॉकर मॅन्युअली चालवण्यासाठी matchstick रेपॉजिटरीमधील सूचनांचे अनुसरण करू शकता.
❗ जर तुम्ही यापूर्वी ग्राफ चाचणी
केली असेल तर तुम्हाला डॉकर बिल्ड दरम्यान खालील त्रुटी येऊ शकते:
प्रेषकाकडून त्रुटी: xattr node_modules/binary-install-raw/bin/binary करण्यात अयशस्वी-<platform>: परवानगी नाकारली
या प्रकरणात रूट फोल्डरमध्ये .dockerignore
तयार करा आणि node_modules/binary-install-raw/bin
जोडा
मॅचस्टिक matchstick.yaml
कॉन्फिगर फाइलद्वारे सानुकूल चाचण्या, libs आणि मॅनिफेस्ट पथ वापरण्यासाठी कॉन्फिगर केले जाऊ शकते:
testsFolder: path/to/tests
libsFolder: path/to/libs
manifestPath: path/to/subgraph.yaml
तुम्ही डेमो सबग्राफ रेपो क्लोन करून या मार्गदर्शकातील उदाहरणे वापरून पाहू शकता आणि खेळू शकता
तसेच तुम्ही "तुमच्या सबग्राफसाठी युनिट चाचण्या लिहिण्यासाठी मॅचस्टिक कसे वापरावे" वर व्हिडिओ मालिका पाहू शकता
महत्त्वाचे: >=0.5.0 म्हणून मॅचस्टिक आवश्यक आहे
describe(name: String , () => {})
- Defines a test group.
नोट्स:
- वर्णने अनिवार्य नाहीत. तुम्ही describe() ब्लॉक्सच्या बाहेर test() जुन्या पद्धतीने अजूनही वापरू शकता
उदाहरण:
import { describe, test } from "matchstick-as/assembly/index"
import { handleNewGravatar } from "../../src/gravity"
describe("handleNewGravatar()", () => {
test("Should create a new Gravatar entity", () => {
...
})
})
नेस्टेड describe()
उदाहरण:
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)
- Defines a test case. You can use test() inside of describe() blocks or independently.
उदाहरण:
import { describe, test } from "matchstick-as/assembly/index"
import { handleNewGravatar } from "../../src/gravity"
describe("handleNewGravatar()", () => {
test("Should create a new Entity", () => {
...
})
})
किंवा
test("handleNewGravatar() should create a new entity", () => {
...
})
फाइलमधील कोणत्याही चाचण्यांपूर्वी कोड ब्लॉक चालवते. describe
ब्लॉकच्या आत before All
घोषित केले असल्यास, ते त्या describe
ब्लॉकच्या सुरुवातीला चालते.
उदाहरणे:
आधी सर्व
मध्ये कोड फाइलमधील सर्व चाचण्यांपूर्वी एकदा कार्यान्वित होईल.
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", () => {
...
})
})
foreAll
मधील कोड पहिल्या वर्णन ब्लॉकमधील सर्व चाचण्यांपूर्वी एकदा कार्यान्वित होईल
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", () => {
...
})
})
फाइलमधील सर्व चाचण्यांनंतर कोड ब्लॉक चालवते. वर्णन
ब्लॉकच्या आत आफ्टरऑल
घोषित केले असल्यास, ते त्या वर्णन
ब्लॉकच्या शेवटी चालते.
उदाहरण:
आफ्टरऑल
मध्ये कोड फाइलमधील सर्व चाचण्यांनंतर एकदा कार्यान्वित होईल.
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
मधील कोड पहिल्या वर्णन ब्लॉकमधील सर्व चाचण्यांनंतर एकदाच कार्यान्वित होईल
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", () => {
...
})
})
प्रत्येक चाचणीपूर्वी कोड ब्लॉक चालवते. describe
ब्लॉकच्या आत beforeEach
घोषित केले असल्यास, ते त्या describe
ब्लॉकमधील प्रत्येक चाचणीपूर्वी चालते.
उदाहरणे: प्रत्येक चाचण्यांपूर्वी beforeEach
मधील कोड कार्यान्वित होईल.
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
मधील कोड वर्णन केलेल्या प्रत्येक चाचणीपूर्वीच कार्यान्वित होईल
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')
// code that should update the displayName to 1st Gravatar
assert.fieldEquals('Gravatar', '0x0', 'displayName', '1st Gravatar')
store.remove('Gravatar', '0x0')
})
test('Updates the imageUrl', () => {
assert.fieldEquals('Gravatar', '0x0', 'imageUrl', '')
// code that should changes the imageUrl to https://www.gravatar.com/avatar/0x0
assert.fieldEquals('Gravatar', '0x0', 'imageUrl', 'https://www.gravatar.com/avatar/0x0')
store.remove('Gravatar', '0x0')
})
})
प्रत्येक चाचणीनंतर कोड ब्लॉक चालवते. describe
ब्लॉकमध्ये afterEach
घोषित केले असल्यास, ते त्या describe
ब्लॉकमधील प्रत्येक चाचणीनंतर चालते.
उदाहरणे:
प्रत्येक चाचणीनंतर afterEach
मधील कोड कार्यान्वित होईल.
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")
// code that should update the displayName to 1st Gravatar
assert.fieldEquals("Gravatar", "0x0", "displayName", "1st Gravatar")
})
test("Updates the imageUrl", () => {
assert.fieldEquals("Gravatar", "0x0", "imageUrl", "")
// code that should changes the imageUrl to https://www.gravatar.com/avatar/0x0
assert.fieldEquals("Gravatar", "0x0", "imageUrl", "https://www.gravatar.com/avatar/0x0")
})
})
afterEach
मधील कोड त्या वर्णनातील प्रत्येक चाचणीनंतर कार्यान्वित होईल
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")
// code that should update the displayName to 1st Gravatar
assert.fieldEquals("Gravatar", "0x0", "displayName", "1st Gravatar")
})
test("Updates the imageUrl", () => {
assert.fieldEquals("Gravatar", "0x0", "imageUrl", "")
// code that should changes the imageUrl to https://www.gravatar.com/avatar/0x0
assert.fieldEquals("Gravatar", "0x0", "imageUrl", "https://www.gravatar.com/avatar/0x0")
})
})
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)
डेमो सबग्राफ मधील Gravatar उदाहरणे वापरून एक साधी युनिट चाचणी कशी दिसते ते पाहू.
असे गृहीत धरून की आमच्याकडे खालील हँडलर फंक्शन आहे (आपले जीवन सोपे करण्यासाठी दोन मदतनीस कार्यांसह):
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
}
आम्हाला आमच्या प्रोजेक्टमध्ये प्रथम चाचणी फाइल तयार करावी लागेल. ते कसे दिसू शकते याचे हे उदाहरण आहे:
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', () => {
// Create a test entity and save it in the store as initial state (optional)
let gravatar = new Gravatar('gravatarId0')
gravatar.save()
// Create mock events
let newGravatarEvent = createNewGravatarEvent(12345, '0x89205A3A3b2A69De6Dbf7f01ED13B2108B2c43e7', 'cap', 'pac')
let anotherGravatarEvent = createNewGravatarEvent(3546, '0x89205A3A3b2A69De6Dbf7f01ED13B2108B2c43e7', 'cap', 'pac')
// Call mapping functions passing the events we just created
handleNewGravatars([newGravatarEvent, anotherGravatarEvent])
// Assert the state of the store
assert.fieldEquals('Gravatar', 'gravatarId0', 'id', 'gravatarId0')
assert.fieldEquals('Gravatar', '12345', 'owner', '0x89205A3A3b2A69De6Dbf7f01ED13B2108B2c43e7')
assert.fieldEquals('Gravatar', '3546', 'displayName', 'cap')
// Clear the store in order to start the next test off on a clean slate
clearStore()
})
test('Next test', () => {
//...
})
अनपॅक करण्यासाठी ते खूप आहे! सर्वप्रथम, लक्षात घेण्यासारखी महत्त्वाची गोष्ट म्हणजे आम्ही आमच्या असेंबलीस्क्रिप्ट हेल्पर लायब्ररी (npm मॉड्यूल म्हणून वितरित) matchstick-as
मधून गोष्टी आयात करत आहोत. तुम्ही येथे भांडार शोधू शकता. matchstick-as
आम्हाला उपयुक्त चाचणी पद्धती प्रदान करते आणि test()
फंक्शन देखील परिभाषित करते जे आम्ही आमचे चाचणी ब्लॉक तयार करण्यासाठी वापरू. बाकीचे अगदी सरळ आहे - काय होते ते येथे आहे:
- आम्ही आमची प्रारंभिक स्थिती सेट करत आहोत आणि एक कस्टम Gravatar अस्तित्व जोडत आहोत;
- आम्ही
createNewGravatarEvent()
फंक्शन वापरून दोनNewGravatar
इव्हेंट ऑब्जेक्ट्स त्यांच्या डेटासह परिभाषित करतो; - आम्ही त्या इव्हेंटसाठी हँडलर पद्धती कॉल करत आहोत -
handleNewGravatars()
आणि आमच्या सानुकूल इव्हेंटच्या सूचीमध्ये पास करत आहोत; - आम्ही स्टोअरच्या स्थितीवर ठाम आहोत. ते कसे कार्य करते? - आम्ही अस्तित्व प्रकार आणि आयडीचे एक अद्वितीय संयोजन पास करत आहोत. मग आम्ही त्या घटकावरील विशिष्ट फील्ड तपासतो आणि असे प्रतिपादन करतो की तिच्याकडे अपेक्षित मूल्य आहे. आम्ही स्टोअरमध्ये जोडलेल्या सुरुवातीच्या Gravatar एंटिटीसाठी तसेच हँडलर फंक्शन कॉल केल्यावर जोडल्या जाणार्या दोन Gravatar घटकांसाठी आम्ही हे करत आहोत;
- आणि शेवटी - आम्ही
clearStore()
वापरून स्टोअर साफ करत आहोत जेणेकरून आमची पुढील चाचणी नवीन आणि रिकाम्या स्टोअर ऑब्जेक्टसह सुरू होईल. आम्हाला पाहिजे तितके चाचणी ब्लॉक्स आम्ही परिभाषित करू शकतो.
आम्ही तिथे जातो - आम्ही आमची पहिली चाचणी तयार केली आहे! 👏
आता आमच्या चाचण्या चालवण्यासाठी तुम्हाला तुमच्या सबग्राफ रूट फोल्डरमध्ये खालील गोष्टी चालवाव्या लागतील:
आलेख चाचणी गुरुत्वाकर्षण
आणि जर सर्व काही ठीक झाले तर तुम्हाला पुढील गोष्टींसह स्वागत केले पाहिजे:
वापरकर्ते ज्ञात घटकांच्या संचासह स्टोअर हायड्रेट करण्यास सक्षम आहेत. Gravatar घटकासह स्टोअर सुरू करण्यासाठी येथे एक उदाहरण आहे:
let gravatar = new Gravatar('entryId')
gravatar.save()
वापरकर्ता सानुकूल इव्हेंट तयार करू शकतो आणि स्टोअरला बांधील असलेल्या मॅपिंग फंक्शनमध्ये पास करू शकतो:
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)
वापरकर्ते चाचणी फिक्स्चरसह मॅपिंग कॉल करू शकतात.
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);
});
}
वापरकर्ते कॉन्ट्रॅक्ट कॉलची थट्टा करू शकतात:
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))
दाखवल्याप्रमाणे, कॉन्ट्रॅक्ट कॉलची थट्टा करण्यासाठी आणि रिटर्न व्हॅल्यू हार्डकोर करण्यासाठी, वापरकर्त्याने कॉन्ट्रॅक्ट अॅड्रेस, फंक्शनचे नाव, फंक्शन सिग्नेचर, वितर्कांची अॅरे आणि अर्थातच - रिटर्न व्हॅल्यू प्रदान करणे आवश्यक आहे.
वापरकर्ते फंक्शन रिव्हर्ट्सची थट्टा देखील करू शकतात:
द्या कॉन्ट्रॅक्ट अॅड्रेस = Address.fromString('0x89205A3A3b2A69De6Dbf7f01ED13B2108B2c43e7')
createMockedFunction(contractAddress, 'getGravatar', 'getGravatar(address):(string,string)')
.withArgs([ethereum.Value.fromAddress(contractAddress)])
.परत करते()
वापरकर्ते mockIpfsFile(hash, filePath)
फंक्शन वापरून IPFS फाइल्सची थट्टा करू शकतात. फंक्शन दोन आर्ग्युमेंट्स स्वीकारते, पहिला आयपीएफएस फाइल हॅश/पथ आणि दुसरा स्थानिक फाइलचा मार्ग आहे.
टीप: ipfs.map/ipfs.mapJSON
ची चाचणी करताना, मॅचस्टॅकने processGravatar()
फंक्शन सारखे शोधण्यासाठी चाचणी फाइलमधून कॉलबॅक फंक्शन एक्सपोर्ट केले पाहिजे. खालील चाचणी उदाहरणामध्ये:
.test.ts
फाइल:
import { assert, test, mockIpfsFile } from 'matchstick-as/assembly/index'
import { ipfs } from '@graphprotocol/graph-ts'
import { gravatarFromIpfs } from './utils'
// Export ipfs.map() callback in order for matchstck to detect it
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
फाइल:
import { Address, ethereum, JSONValue, Value, ipfs, json, Bytes } from "@graphprotocol/graph-ts"
import { Gravatar } from "../../generated/schema"
...
// ipfs.map callback
export function processGravatar(value: JSONValue, userData: Value): void {
// See the JSONValue documentation for details on dealing
// with JSON values
let obj = value.toObject()
let id = obj.get('id')
if (!id) {
return
}
// Callbacks can also created entities
let gravatar = new Gravatar(id.toString())
gravatar.displayName = userData.toString() + id.toString()
gravatar.save()
}
// function that calls ipfs.cat
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()
}
वापरकर्ते दावा करणार्या संस्थांद्वारे स्टोअरची अंतिम (किंवा मिडवे) स्थिती सांगू शकतात. हे करण्यासाठी, वापरकर्त्याला एंटिटी प्रकार, एंटिटीचा विशिष्ट आयडी, त्या घटकावरील फील्डचे नाव आणि फील्डचे अपेक्षित मूल्य पुरवावे लागेल. येथे एक द्रुत उदाहरण आहे:
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() फंक्शन चालवल्याने दिलेल्या फील्डची दिलेल्या अपेक्षित मूल्याविरुद्ध समानता तपासली जाईल. चाचणी अयशस्वी होईल आणि मूल्ये नाही समान असल्यास एक त्रुटी संदेश आउटपुट केला जाईल. अन्यथा चाचणी यशस्वीरित्या उत्तीर्ण होईल.
वापरकर्ते डीफॉल्ट व्यवहार मेटाडेटा वापरू शकतात, जो इथरियम म्हणून परत केला जाऊ शकतो. newMockEvent()
फंक्शन वापरून इव्हेंट. खालील उदाहरण इव्हेंट ऑब्जेक्टवरील त्या फील्डवर तुम्ही कसे वाचू/लिहू शकता हे दाखवते:
// Read
let logType = newGravatarEvent.logType
// Write
let UPDATED_ADDRESS = '0xB16081F360e3847006dB660bae1c6d1b2e17eC2A'
newGravatarEvent.address = Address.fromString(UPDATED_ADDRESS)
assert.equals(ethereum.Value.fromString("hello"); ethereum.Value.fromString("hello"));
वापरकर्ते असे ठामपणे सांगू शकतात की स्टोअरमध्ये अस्तित्व नाही. फंक्शन एक अस्तित्व प्रकार आणि आयडी घेते. वस्तुस्थिती स्टोअरमध्ये असल्यास, चाचणी संबंधित त्रुटी संदेशासह अयशस्वी होईल. ही कार्यक्षमता कशी वापरायची याचे एक द्रुत उदाहरण येथे आहे:
assert.notInStore('Gravatar', '23')
हे हेल्पर फंक्शन वापरून तुम्ही संपूर्ण स्टोअर कन्सोलवर मुद्रित करू शकता:
import { logStore } from 'matchstick-as/assembly/store'
logStore()
चाचणी() फंक्शन्सवर shouldFail ध्वज वापरून वापरकर्त्यांना अपेक्षित चाचणी अपयश येऊ शकते:
test(
'Should throw an error',
() => {
throw new Error()
},
true,
)
जर चाचणी shouldFail = true सह चिन्हांकित केली असेल परंतु अयशस्वी होत नसेल, तर ती लॉगमध्ये त्रुटी म्हणून दिसून येईल आणि चाचणी ब्लॉक अयशस्वी होईल. तसेच, जर हे shouldFail = false (डिफॉल्ट स्थिती) ने चिन्हांकित केले असेल, तर चाचणी निष्पादक क्रॅश होईल.
युनिट चाचण्यांमध्ये सानुकूल लॉग असणे हे मॅपिंगमध्ये लॉग इन करण्यासारखेच आहे. फरक असा आहे की लॉग ऑब्जेक्ट ग्राफ-टीएस ऐवजी मॅचस्टिक-एज वरून आयात करणे आवश्यक आहे. सर्व गैर-गंभीर लॉग प्रकारांसह येथे एक साधे उदाहरण आहे:
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!", []);
});
वापरकर्ते गंभीर अपयशाचे अनुकरण देखील करू शकतात, जसे की:
test('Blow everything up', () => {
log.critical('Boom!')
})
गंभीर त्रुटी लॉग केल्याने चाचण्यांची अंमलबजावणी थांबेल आणि सर्वकाही उडून जाईल. शेवटी - आम्ही हे सुनिश्चित करू इच्छितो की तुमच्या कोडमध्ये डिप्लॉयमेंटमध्ये गंभीर नोंदी नाहीत, आणि तसे झाल्यास तुम्हाला लगेच लक्षात येईल.
व्युत्पन्न फील्डची चाचणी करणे हे एक वैशिष्ट्य आहे जे वापरकर्त्यास विशिष्ट घटकामध्ये फील्ड सेट करण्यास अनुमती देते आणि जर ती प्रथम घटकाकडून फील्ड प्राप्त केली असेल तर ती स्वयंचलितपणे अद्यतनित केली जाईल. लक्षात घेण्याजोगी महत्त्वाची गोष्ट अशी आहे की पहिल्या घटकाला रीलोड करणे आवश्यक आहे कारण स्टोअरमध्ये स्वयंचलित अपडेट गंजलेल्या स्थितीत होते ज्याचा AS कोड अज्ञेयवादी आहे.
test('Derived fields example test', () => {
let mainAccount = new GraphAccount('12')
mainAccount.save()
let operatedAccount = new GraphAccount('1')
operatedAccount.operators = ['12']
operatedAccount.save()
let nst = new NameSignalTransaction('1234')
nst.signer = '12'
nst.save()
assert.assertNull(mainAccount.get('nameSignalTransactions'))
assert.assertNull(mainAccount.get('operatorOf'))
mainAccount = GraphAccount.load('12')!
assert.i32Equals(1, mainAccount.nameSignalTransactions.length)
assert.stringEquals('1', mainAccount.operatorOf[0])
})
डायनॅमिक डेटा स्रोतांची चाचणी context()
, address()
आणि network()
फंक्शन्सच्या रिटर्न व्हॅल्यूची थट्टा करून केली जाऊ शकते. डेटास्रोत नेमस्पेस. ही फंक्शन्स सध्या खालील गोष्टी परत करतात: संदर्भ()
- रिक्त अस्तित्व (डेटास्रोत संदर्भ), पत्ता()
परत करते - 0x00000000000000000000000000000000000000
, नेटवर्क() -
मेननेट
परत करतो.create(...)
आणि createWithContext(...)
फंक्शन्सची थट्टा केली जाते की काहीही करू नये म्हणून त्यांना चाचणीमध्ये बोलावण्याची गरज नाही. रिटर्न व्हॅल्यूजमधील बदल matchstick-as
मधील dataSourceMock
नेमस्पेसच्या फंक्शन्सद्वारे केले जाऊ शकतात (आवृत्ती 0.3.0+).
खालील उदाहरण:
प्रथम आमच्याकडे खालील इव्हेंट हँडलर आहे (जे जाणूनबुजून डेटासोर्स मस्करी दाखवण्यासाठी पुन्हा केले गेले आहे):
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()
}
आणि मग डेटासोर्सच्या सर्व फंक्शन्ससाठी नवीन रिटर्न व्हॅल्यू सेट करण्यासाठी dataSourceMock नेमस्पेसमधील पद्धतींपैकी एक वापरून आमच्याकडे चाचणी आहे:
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() कॉल केला आहे. याचे कारण असे की जेव्हा मूल्ये बदलली जातात तेव्हा ती लक्षात ठेवली जातात आणि जर तुम्हाला डीफॉल्ट मूल्यांवर परत जायचे असेल तर ते रीसेट करणे आवश्यक आहे.
Using Matchstick, subgraph developers are able to run a script that will calculate the test coverage of the written unit tests.
The test coverage tool takes the compiled test wasm
binaries and converts them to wat
files, which can then be easily inspected to see whether or not the handlers defined in subgraph.yaml
have been called. Since code coverage (and testing as whole) is in very early stages in AssemblyScript and WebAssembly, Matchstick cannot check for branch coverage. Instead we rely on the assertion that if a given handler has been called, the event/function for it have been properly mocked.
Matchstick मध्ये प्रदान केलेली चाचणी कव्हरेज कार्यक्षमता चालवण्यासाठी, तुम्हाला काही गोष्टी आधीच तयार करणे आवश्यक आहे:
कोणते हँडलर चालवले जात आहेत हे तपासण्यासाठी मॅचस्टिक साठी, त्या हँडलरना चाचणी फाइल मधून निर्यात करणे आवश्यक आहे. उदाहरणार्थ, आमच्या उदाहरणात, आमच्या gravity.test.ts फाइलमध्ये आमच्याकडे खालील हँडलर आयात केले जात आहे:
'../../src/gravity' वरून { handleNewGravatar } आयात करा
ते कार्य दृश्यमान होण्यासाठी (ते wat
फाइल नावाने मध्ये समाविष्ट करण्यासाठी) आम्हाला ते निर्यात देखील करावे लागेल, जसे:
निर्यात { handleNewGravatar }
एकदा ते सर्व सेट झाल्यानंतर, चाचणी कव्हरेज साधन चालविण्यासाठी, फक्त चालवा:
आलेख चाचणी-- -c
तुम्ही तुमच्या package.json
फाईलमध्ये सानुकूल कव्हरेज
कमांड देखील जोडू शकता, जसे की:
"scripts": {
/.../
"coverage": "graph test -- -c"
},
That will execute the coverage tool and you should see something like this in the terminal:
$ आलेख चाचणी -c
डाउनलोड/इंस्टॉल चरण वगळणे कारण /Users/petko/work/demo-subgraph/node_modules/binary-install-raw/bin/0.4.0 वर बायनरी आधीपासूनच अस्तित्वात आहे
___ ___ _ _ _ _ _
| \/ | | | | | | | (_) | |
| . . | __ _| |_ ___| |__ ___| |_ _ ___| | __
| |\/| |/ _` | __/ __| '_ \/ __| __| |/ __| |//
| | | | (_| | || (__| | | \__ \ |_| | (__| <
\_| |_/\__,__|\__\___|__| |_|___/\__|_|\___|_|\_\
संकलित करत आहे...
कव्हरेज रिपोर्ट मोडमध्ये चालत आहे.
️
व्युत्पन्न चाचणी मॉड्यूल्स वाचत आहे... 🔎️
कव्हरेज अहवाल व्युत्पन्न करत आहे 📝
'ग्रॅव्हिटी' स्त्रोतासाठी हँडलर:
हँडलर 'हँडलन्यूग्रावतार' चाचणी केली जाते.
हँडलर 'handleUpdatedGravatar' ची चाचणी केलेली नाही.
हँडलर 'handleCreateGravatar' चाचणी केली आहे.
चाचणी कव्हरेज: 66.7% (2/3 हँडलर).
'GraphTokenLockWallet' स्त्रोतासाठी हँडलर:
हँडलर 'हँडलटोकन्सरिलीझ्ड' ची चाचणी केलेली नाही.
हँडलर 'HandleTokensWithdrawn' ची चाचणी केली जात नाही.
हँडलर 'HandleTokensRevoked' ची चाचणी केलेली नाही.
हँडलर 'handleManagerUpdated' चाचणी केलेली नाही.
हँडलर 'handleApproveTokenDestinations' ची चाचणी केलेली नाही.
हँडलर 'handleRevokeTokenDestinations' ची चाचणी केलेली नाही.
चाचणी कव्हरेज: 0.0% (0/6 हँडलर).
जागतिक चाचणी कव्हरेज: 22.2% (2/9 हँडलर).
लॉग आउटपुटमध्ये चाचणी रन कालावधी समाविष्ट आहे. येथे एक उदाहरण आहे:
[गुरु, 31 मार्च 2022 13:54:54 +0300] प्रोग्राम अंमलात आणला: 42.270ms.
गंभीर: संदर्भासह वैध मॉड्यूलमधून WasmInstance तयार करू शकलो नाही: अज्ञात आयात: wasi_snapshot_preview1::fd_write परिभाषित केले गेले नाही
याचा अर्थ तुम्ही तुमच्या कोडमध्ये console.log
वापरले आहे, जे असेंबलीस्क्रिप्टद्वारे समर्थित नाही. कृपया लॉगिंग API वापरण्याचा विचार करा
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)
त्रुटी TS2554: अपेक्षित आहे? युक्तिवाद, पण मिळाले?.
नवीन ethereum.Transaction परत करा(defaultAddressBytes, defaultBigInt, defaultAddress, defaultAddress, defaultBigInt, defaultBigInt, defaultBigInt, defaultAddressBytes, defaultBigInt);
in ~lib/matchstick-as/assembly/defaults.ts(24,12)
graph-ts
आणि matchstick-as
मधील जुळत नसल्यामुळे वितर्कांमधील जुळत नाही. यासारख्या समस्यांचे निराकरण करण्याचा सर्वोत्तम मार्ग म्हणजे नवीनतम रिलीझ केलेल्या आवृत्तीवर सर्वकाही अद्यतनित करणे.
तुमच्याकडे काही प्रश्न, अभिप्राय, वैशिष्ट्य विनंत्या असल्यास किंवा फक्त संपर्क साधायचा असल्यास, सर्वोत्तम ठिकाण म्हणजे The Graph Discord जेथे आमच्याकडे Matchstick साठी एक समर्पित चॅनेल आहे, ज्याला 🔥| युनिट-चाचणी.