测试和调试Convector智能合约

  • 时间:
  • 浏览:136
  • 来源:区块链技术网

在开发智能合约的同时,避免浪费时间的任务是明智的。使用Convector,您可以使用Mock分类帐运行本地单元测试,您也可以使用它来调试代码。使用最新版本的Hurley和Convector 智能合约,现在甚至可以直接从区块链进行调试。

 

单元测试

什么是单元测试?

 

通常,您会获取一段代码单元来进行测试(一个模块、一个函数、一组函数)并编写调用该函数并检查结果的函数。这些测试可以在编译、集成或部署代码时运行,这样您就可以确保预期发生的事情仍然会发生。

 

整体单元测试可以为您节省大量时间和金钱,同时还可以帮助您保持健康的代码库。

 

如何操作

首先安装Convector-CLI, 一定要有Node 8.11.0和Docker Community Edition。

 

确保您的是Convector-CLI 1.1.0版

 

npm i -g @worldsibu/convector-cli

现在,让我们从创建一个新的Convector项目开始:

$ conv new bughunting -c mybuggychaincode
$ cd bughunting
$ npm install

测试

默认情况下,为./packages/mybuggychaincode/tests/mybuggychaincode.spec.ts中的链代码创建了一个测试文件。

 

我们使用mocha进行测试,这是一个着名的lib。 该文件只是带来管道并测试控制器具有的默认创建功能。

 

 在你的终端运行npm run test

 

 您刚刚为Convector智能合约进行了第一次单元测试。 这也是您的CI / CD过程中自动运行的内容。

 

mocha应用相当广泛,您可以在这里查看所有选项。 现在,让我们创建一个额外的功能并稍微改变智能合约。

 

相应地更新以下文件mybuggychaincode.controller.ts,mybuggychaincode.model.ts和mybuggychaincode.spec.ts:

 

import {
  Controller,
  ConvectorController,
  Invokable,
  Param
from '@worldsibu/convector-core';
import * as yup from 'yup';
import { Mybuggychaincode } from './mybuggychaincode.model';

@Controller('mybuggychaincode')
export class MybuggychaincodeController extends ConvectorController {

  @Invokable()
  public async create(
    @Param(Mybuggychaincode)
    mybuggychaincode: Mybuggychaincode
  ) {
    console.log(`sender=${this.sender}`);
    mybuggychaincode.owner = this.sender;
    await mybuggychaincode.save();
    return mybuggychaincode;
  }

  @Invokable()
  public async getOne(
    @Param(yup.string())
    id: string
  ) {
    return await Mybuggychaincode.getOne(id);
  }

  @Invokable()
  public async update(
    @Param(Mybuggychaincode)
    mybuggychaincode: Mybuggychaincode
  ) {
    let existingModel = await Mybuggychaincode.getOne(mybuggychaincode.id);

    if (!existingModel.id) {
      throw new Error(`Item with ${mybuggychaincode.id} doesn't exist in the blockchain!`);
    }
    console.log(existingModel);
    console.log(`${existingModel.owner} ${this.sender}`)
    if (existingModel.owner !== this.sender) {
      throw new Error(`Ups, the requesting identity is not authorized to update the model`);
    }

    // Make changes
    existingModel.name = mybuggychaincode.name;

    await existingModel.save();
    console.log(existingModel);
    return existingModel;
  }
}

mybuggychaincode.controller.ts 

import * as yup from 'yup';
import {
  ConvectorModel,
  Default,
  ReadOnly,
  Required,
  Validate
} from '@worldsibu/convector-core';

export class Mybuggychaincode extends ConvectorModel<Mybuggychaincode{
  @ReadOnly()
  @Required()
  public readonly type = 'io.worldsibu.mybuggychaincode';

  @Required()
  @Validate(yup.string())
  public name: string;

  @Validate(yup.string())
  public owner: string;

  @ReadOnly()
  @Required()
  @Validate(yup.number())
  public created: number;

  @Required()
  @Validate(yup.number())
  public modified: number;
}

mybuggychaincode.model.ts 

// tslint:disable:no-unused-expression
import { join } from 'path';
import * as chai from 'chai';
import { expect } from 'chai';
import * as uuid from 'uuid/v4';
import { MockControllerAdapter } from '@worldsibu/convector-adapter-mock';
import 'mocha';
import * as chaiAsPromised from 'chai-as-promised';
import { Mybuggychaincode } from '../src/mybuggychaincode.model';
import { ChaincodeMockStub } from '@theledger/fabric-mock-stub';
import { MybuggychaincodeController } from '../src';
import { ClientFactory } from '@worldsibu/convector-core';

describe('Mybuggychaincode'async () => {
    chai.use(chaiAsPromised);
    let modelSample: Mybuggychaincode;
    let adapter: MockControllerAdapter;
    let mybuggychaincodeCtrl: MybuggychaincodeController;

    let modelId = uuid();
    // By default, MockControllerAdapter will use this fingerprint as the `this.sender`
    const mockIdentity = 'B6:0B:37:7C:DF:D2:7A:08:0B:98:BF:52:A4:2C:DC:4E:CC:70:91:E1';

    before(async () => {
        const now = new Date().getTime();
        modelSample = new Mybuggychaincode();
        modelSample.id = modelId;
        modelSample.name = 'Test';
        modelSample.created = now;
        modelSample.modified = now;
        // Mocks the blockchain execution environment
        adapter = new MockControllerAdapter();
        await adapter.init([
            {
                version'*',
                controller'MybuggychaincodeController',
                name: join(__dirname, '..')
            }
        ]);
        mybuggychaincodeCtrl = ClientFactory(MybuggychaincodeController, adapter);
    });

    it('should create a default model'async () => {
        await mybuggychaincodeCtrl.create(modelSample);

        const justSavedModel = await adapter.getById<Mybuggychaincode>(modelSample.id);

        expect(justSavedModel.id).to.exist;
    });

    it('should find the model'async () => {
        let result = new Mybuggychaincode(
            await mybuggychaincodeCtrl
                .getOne(modelId));
        console.log(result);
        expect(result.id).to.exist;
    });

    it('try to update without success'async () => {
        // Fake a different identity sending the transaction
        (adapter.stub as any).usercert = '-----BEGIN CERTIFICATE-----' +
            'MIICjzCCAjWgAwIBAgIUITsRsw5SIJ+33SKwM4j1Dl4cDXQwCgYIKoZIzj0EAwIw' +
            'czELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNh' +
            'biBGcmFuY2lzY28xGTAXBgNVBAoTEG9yZzEuZXhhbXBsZS5jb20xHDAaBgNVBAMT' +
            'E2NhLm9yZzEuZXhhbXBsZS5jb20wHhcNMTgwODEzMDEyOTAwWhcNMTkwODEzMDEz' +
            'NDAwWjBCMTAwDQYDVQQLEwZjbGllbnQwCwYDVQQLEwRvcmcxMBIGA1UECxMLZGVw' +
            'YXJ0bWVudDExDjAMBgNVBAMTBXVzZXIzMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcD' +
            'QgAEcrfc0HHq5LG1UbyPSRLNjIQKqYoNY7/zPFC3UTJi3TTaIEqgVL6DF/8JIKuj' +
            'IT/lwkuemafacXj8pdPw3Zyqs6OB1zCB1DAOBgNVHQ8BAf8EBAMCB4AwDAYDVR0T' +
            'AQH/BAIwADAdBgNVHQ4EFgQUHFUlW/XJC7VcJe5pLFkz+xlMNpowKwYDVR0jBCQw' +
            'IoAgQ3hSDt2ktmSXZrQ6AY0EK2UHhXMx8Yq6O7XiA+X6vS4waAYIKgMEBQYHCAEE' +
            'XHsiYXR0cnMiOnsiaGYuQWZmaWxpYXRpb24iOiJvcmcxLmRlcGFydG1lbnQxIiwi' +
            'aGYuRW5yb2xsbWVudElEIjoidXNlcjMiLCJoZi5UeXBlIjoiY2xpZW50In19MAoG' +
            'CCqGSM49BAMCA0gAMEUCIQCNsmDjOXF/NvciSZebfk2hfSr/v5CqRD7pIHCq3lIR' +
            'lwIgPC/qGM1yeVinfN0z7M68l8rWn4M4CVR2DtKMpk3G9k9=' +
            '-----END CERTIFICATE-----';

        await expect(mybuggychaincodeCtrl.update(modelSample)).to.be.eventually
            .rejectedWith('Ups, the requesting identity is not authorized to update the model');
    });

    it('try to update with success'async () => {
        // Fake to the correct identity again
        adapter.stub['fingerprint'] = mockIdentity;

        await expect(async () => await mybuggychaincodeCtrl.update(modelSample)
            .then((result) => expect(result.id).to.exist,
                (ex) => expect.fail('Should not have failed')));
    });
});

mybuggychaincode.spec.ts

 

继续进行测试:

 

$ npm test

4个测试功能应该已成功运行!

 

调试

调试是另一个有用的任务,使用Convector Suite可以调试单元测试,但也可以调试在区块链中运行的代码

 

调试单元测试

 

转到./packages/mybuggychaincode-cc/package.json并使用以下内容替换测试任务的内容。

 

"test""npm run build && mocha --inspect --debug=8888 -r ts-node/register tests/*.spec.ts --reporter spec"

--inspect param将允许您连接调试器并遍历您的代码。 我还更改了端口以避免与其他进程发生冲突。

 

您可以使用首选的调试器。我喜欢在节点使用chrome devtools,所以我只需在浏览器中访问chrome://inspect并单击打开节点专用devtools。

 

单击Add connection并输入localhost:8888以侦听该端口。

 

回到您的代码,并在位于./packages/mybuggychaincode/tests/mybuggychaincode.spec.ts中的测试文件中,将调试器放在某处。

 

运行npm test! 您现在应该能够很顺畅地调试您的代码。

 

在区块链中调试代码

我们使用Hurley,从1.0.0开始它现在支持调试参数。

您将在CLI中需要两个新任务(如果您还没有它们)。 转到你的root package.json并查找cc:start:debug和cc:install:debug。

 

npm run cc:start:debug — mybuggychaincode

如果你看到这个,它就准备好进行调试了。

 

在9990中监听调试端口。

 

您现在需要做的就是对要配置的容器和加载的代码进行虚拟调用。

 

# It will throw an expected error - This will take some seconds while downloading dependencies again in the rest of the organizations
$ hurl invoke mybuggychaincode init

现在转到DevTools并探索源代码。

您将看到正在运行的本机代码:

 

在此处查找完整的源代码:https://github.com/worldsibu/convector-example-unit-tests

猜你喜欢

区块链红利吃饱后,这个巨头又想"征服"元宇宙?

据12月26日消息,百度与英伟达(NVIDIA)已达成协议,双方合作共建AI元宇宙。另外,在今日举行的百度AI开发者大会上,英伟达全球副总裁暨亚太区总裁 Raymond Teh将受邀出席,并发表主题演讲。

2021-12-27

2021年,区块链股权融资发生了怎么样的演变

过去一年,区块链行业融资井喷,在科技领域中独树一帜,A16z、红杉、老虎基金等等这些顶级机构在 2021 年的区块链行业肆意驰骋,在 DeFi、NFT、Metaverse 等领域扶持了一众创业项目。

2021-12-23

两个元宇宙的世界观,以及和区块链的关系

“元宇宙”这个名词音好听但义很难传达准确,想要更准确地理解义,取名为平行宇宙、竞争宇宙、山寨宇宙,更好。对应的,我们现在肉身所处的宇宙,我们称之为“肉身宇宙”。

2021-12-22

Alien Worlds(外星世界)区块链打金挖矿指南

Alien Worlds(外星世界)是一款4月就开始的游戏,10月27日又上线了全新的任务(Missions)游戏模式; 在WAX用户量排名中Alien Worlds(外星世界)一直排在前三,说明现在存量工作室还有很多;

2021-12-17

DeHorizon(地平线)区块链打金教程

今天我们就解析在一款社交主题游戏 — DeHorizon

2021-12-17