62solidity环境搭建编译及编写合约-3——2020年07月12日12:55:51

Posted oneapple

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了62solidity环境搭建编译及编写合约-3——2020年07月12日12:55:51相关的知识,希望对你有一定的参考价值。

2020年07月12日12:59:00

2019年09月27日14:15:32

1.通过solc工具编译合约

1.1 先在vscode里创建sol文件

pragma solidity ^0.4.24;
	contract Immo{
    address public ceo;
    constructor() public {
      ceo=msg.sender;
    }
    
  }

1.2.准备编译环境,sol文件都是通过solc工具编译的

npm install solc@0.4.24 --save一定要声明版本

github.com/ethereum/solc-js

1.3.项目是通过react新建的

create-react-app imooc-on-blockchain

1.4.js脚本文件读写和编译sol

mkdir scripts

touch compile.js

// 文件模块
const fs = require(‘fs‘)

const path = require(‘path‘)
//编译模块solc
const solc = require(‘solc‘)

const contractPath = path.resolve(__dirname,‘../contracts/Imooc.sol‘)

// 获取合约文件内容
const source = fs.readFileSync(contractPath,‘utf-8‘)
// 编译
const ret = solc.compile(source)
// console.log(ret)
  Object.keys(ret.contracts).forEach(name=>{
    //过滤掉第一个key键,它前面有一个:,不需要
    const contractName = name.slice(1)
    //创建即将要写进数据的文件路径
    const filePath = path.resolve(__dirname, `../src/compiled/${contractName}.json`)
    //同步写数据
    fs.writeFileSync(filePath,JSON.stringify(ret.contracts[name]))
    console.log(`${filePath} bingo`)
  })

// arr = [{name:‘react‘,content:‘xx‘,{name:‘vue‘,content:‘xx‘}]

1.5.配置package.json

"compile" :"node scripts/compile.js"

技术图片

1.6.启动服务

npm run compile

编译.sol文件,生成一个json(后面部署,测试等需要这些数据)

  1. bytecode

    部署合约用的数据

  2. interface接口声明

    测试使用

2.合约自动编译

  1. 每次compile清空文件,重新生成
  2. 报错信息打印
  3. 能监听,自动compile

2.1 安装rimraf清除模块

npm install rimraf --save

配置package.json

rimraf src/compiled/* && node scripts/compile.js

2.2 控制报错信息

打印出error,发现errors数组长度>1

技术图片

则:

if(Array.isArray(ret.errors) && ret.errors.length>0){
  // 出错了
  console.log(ret.errors[0])
}else{
  Object.keys(ret.contracts).forEach(name=>{
    const contractName = name.slice(1)
    const filePath = path.resolve(__dirname, `../src/compiled/${contractName}.json`)
    fs.writeFileSync(filePath,JSON.stringify(ret.contracts[name]))
    console.log(`${filePath} bingo`)
  })
}

再调式的时候会出现:

技术图片

2.3 使用钩子precompile

在package.json文件中

precompile:"rimraf src/compiled/*"

2.4 监听——使用Onchange模块

npm install onchange --save

"precompile": "rimraf src/compiled/* ",
"compile": "node scripts/compile.js",
"precompile:w": "npm run compile",
"compile:w": "onchange ‘contracts/*.sol‘ -- npm run compile"

只要合约发生了变化,就会重新编译

npm run compile:w

3.编写合约——课程列表

3.1 两个合约:课程数组,单个课程

3.2 方法:新建课程,获取课程

3.3 代码

  pragma solidity ^0.4.24;
  
  contract CourseList{
  address public ceo;
  address[] public courses;
  constructor() public {
    ceo = msg.sender;
  }

  function createCourse(string _name) public{
    address newCourse = new Course(ceo,msg.sender, _name);
    courses.push(newCourse);
  }
  // 获取课程所有地址
  function getCourse() public view returns(address[]){
    return courses;
  }
    }

     contract Course{
        string public name;
        constructor(string _name) public {
            name=_name;
                    }
        }

4.测试合约

4.1 虚拟节点

ganache-cli

4.2测试用的模块

mocha

4.3 编写测试用例
const path = require(‘path‘);
const assert = require(‘assert‘);

describe(‘测试课程的智能‘, () => {

    it(‘测试1+2是否等于3‘, () => {

        assert.equal(1 + 2, 3);
    })
})
4.4 测试合约方法
const path = require(‘path‘);
const assert = require(‘assert‘);
const Web3 = require(‘web3‘)
const ganache = require(‘ganache-cli‘)
//const BigNumber = require(‘bignumber.js‘)
const web3 = new Web3(ganache.provider())
// 引入合约的json
const CourseList = require(path.resolve(__dirname, ‘../src/compiled/CourseList.json‘))
const Course = require(path.resolve(__dirname, ‘../src/compiled/Course.json‘))


// 定义几个全局变量,所有测试都需要
let accounts
// 实例
let courseList
let course

describe(‘测试课程的智能‘, () => {

    before(async () => {
        // 测试前的数据初始化
        accounts = await web3.eth.getAccounts()
        
        console.log(accounts)
        // 1. 虚拟部署一个合约
        courseList = await new web3.eth.Contract(JSON.parse(CourseList.interface))
            .deploy({ data: CourseList.bytecode })
            .send({
                // 最后一个是创建者
                from: accounts[9],
                gas: ‘5000000‘
            })

    })

    it(‘合约部署成功‘, () => {
        assert.ok(courseList.options.address)
    })

    it(‘测试添加课程‘, async () => {
        const oldaddress = await courseList.methods.getCourse().call()
        assert.equal(oldaddress.length, 0)
        await courseList.methods.createCourse(
            ‘蜗牛的React课程‘
        )
            .send({
                from: accounts[0],
                gas: ‘5000000‘
            })
        const address = await courseList.methods.getCourse().call()
        assert.equal(address.length, 1)
				console.log(address)
    })

})
4.5 配置package.json
"test:w": "mocha --watch"
4.6 运行指令

npm run test:w

4.6 测试结果

技术图片

2019年09月27日20:31:07

5.添加删除课程指令

5.1 sol文件里函数编写
 function removeCourse(uint _index) public {
     // 只有ceo能删除
    require(msg.sender == ceo);
    // 根据索引删除
    require(_index<courses.length);
  }
5.2 package.json配置
    "rebuild": "npm run compile && mocha",
    "rebuild:w": "onchange ‘contracts/*.sol‘ ‘test/*.js‘ -- npm run rebuild"

作用是当合约发生变化时,先编译再测试。

5.3 运行

npm run rebuild

5.4 测试用例
const path = require(‘path‘);
const assert = require(‘assert‘);
const Web3 = require(‘web3‘)
const ganache = require(‘ganache-cli‘)
//const BigNumber = require(‘bignumber.js‘)
const web3 = new Web3(ganache.provider())
// 引入合约的json
const CourseList = require(path.resolve(__dirname, ‘../src/compiled/CourseList.json‘))
const Course = require(path.resolve(__dirname, ‘../src/compiled/Course.json‘))


// 定义几个全局变量,所有测试都需要
let accounts
// 实例
let courseList
let course

describe(‘测试课程的智能‘, () => {

    before(async () => {
        // 测试前的数据初始化
        accounts = await web3.eth.getAccounts()

        console.log(accounts)
        // 1. 虚拟部署一个合约
        courseList = await new web3.eth.Contract(JSON.parse(CourseList.interface))
            .deploy({ data: CourseList.bytecode })
            .send({
                // 最后一个是创建者——重点
                from: accounts[9],
                gas: ‘5000000‘
            })

    })

    it(‘合约部署成功‘, () => {
        assert.ok(courseList.options.address)
    })

    it(‘测试添加课程‘, async () => {
        const oldaddress = await courseList.methods.getCourse().call()
        assert.equal(oldaddress.length, 0)
        await courseList.methods.createCourse(
            ‘蜗牛的React课程‘
        )
            .send({
                from: accounts[0],
                gas: ‘5000000‘
            })
        const address = await courseList.methods.getCourse().call()
        assert.equal(address.length, 1)
        console.log(address)

    })

    it("添加课程的属性", async () => {
        const [address] = await courseList.methods.getCourse().call()
        // 添加的课程合约的地址
        course = await new web3.eth.Contract(JSON.parse(Course.interface), address)
        const name = await course.methods.name().call()
        assert.equal(name, ‘蜗牛的React课程‘)
    })



    //删除功能
    it("只能ceo能删", async () => {
        await courseList.methods.createCourse(
            ‘蜗牛的Vue课程‘
        )
            .send({
                from: accounts[0],
                gas: ‘5000000‘
            })
        const address = await courseList.methods.getCourse().call()
        assert.equal(address.length, 2)

      await courseList.methods.removeCourse(0).send({
        from:accounts[9],
        gas:‘5000000‘
      })
      const address1 = await courseList.methods.getCourse().call()
      console.log(address1)
      assert.equal(address1.length,1)
      
    })

})
5.6 发现bug

solidity提供的delete()方法删除了地址账号后,不是清除数据,而是将数据清0.

所以得修改合约里的方法

5.7 修改合约
  function removeCourse(uint _index) public {
     // 只有ceo能删除
    require(msg.sender == ceo);
    // 根据索引删除
    require(_index<courses.length);
    uint len = courses.length;
    for(uint i=_index;i<len-1;i++){
      courses[i] = courses[i+1];
    }
    delete courses[len-1];
    courses.length--;
  }


    }
5.8 添加管理员的认证——合约方法
  function isCeo() public view returns(bool){
    return msg.sender==ceo;
  }
5.9测试用例
  it(‘判断是不是ceo‘,async ()=>{
    const isCeo1 = await courseList.methods.isCeo().call({
      from :accounts[9]
    })
    const isCeo2 = await courseList.methods.isCeo().call({
      from :accounts[1]
    })
    assert.ok(isCeo1)
    assert.ok(!isCeo2)
  })
5.10 运行结果

npm run rebuild:w

技术图片

5.11 完整代码
//Imooc.sol  
pragma solidity ^0.4.24;
  
  contract CourseList{
  address public ceo;
  address[] public courses;
  constructor() public {
    ceo = msg.sender;
  }

  function createCourse(string _name) public{
    address newCourse = new Course(_name);
    courses.push(newCourse);
  }
  // 获取课程所有地址
  function getCourse() public view returns(address[]){
    return courses;
  }

  function removeCourse(uint _index) public {
     // 只有ceo能删除
    require(msg.sender == ceo);
    // 根据索引删除
    require(_index<courses.length);
    uint len = courses.length;
    for(uint i=_index;i<len-1;i++){
      courses[i] = courses[i+1];
    }
    delete courses[len-1];
    courses.length--;
  }
  function isCeo() public view returns(bool){
    return msg.sender==ceo;
  }

    }
     
     
     
contract Course{
    string public name;
    constructor(string _name) public {
        name=_name;
             }
        }
//course.spec.js
const path = require(‘path‘);
const assert = require(‘assert‘);
const Web3 = require(‘web3‘)
const ganache = require(‘ganache-cli‘)
//const BigNumber = require(‘bignumber.js‘)
const web3 = new Web3(ganache.provider())
// 引入合约的json
const CourseList = require(path.resolve(__dirname, ‘../src/compiled/CourseList.json‘))
const Course = require(path.resolve(__dirname, ‘../src/compiled/Course.json‘))


// 定义几个全局变量,所有测试都需要
let accounts
// 实例
let courseList
let course

describe(‘测试课程的智能‘, () => {

    before(async () => {
        // 测试前的数据初始化
        accounts = await web3.eth.getAccounts()

        console.log(accounts)
        // 1. 虚拟部署一个合约
        courseList = await new web3.eth.Contract(JSON.parse(CourseList.interface))
            .deploy({ data: CourseList.bytecode })
            .send({
                // 最后一个是创建者——重点
                from: accounts[9],
                gas: ‘5000000‘
            })

    })

    it(‘合约部署成功‘, () => {
        assert.ok(courseList.options.address)
    })

    it(‘测试添加课程‘, async () => {
        const oldaddress = await courseList.methods.getCourse().call()
        assert.equal(oldaddress.length, 0)
        await courseList.methods.createCourse(
            ‘蜗牛的React课程‘
        )
            .send({
                from: accounts[0],
                gas: ‘5000000‘
            })
        const address = await courseList.methods.getCourse().call()
        assert.equal(address.length, 1)
        console.log(address)

    })

    it("添加课程的属性", async () => {
        const [address] = await courseList.methods.getCourse().call()
        // 添加的课程合约的地址
        course = await new web3.eth.Contract(JSON.parse(Course.interface), address)
        const name = await course.methods.name().call()
        assert.equal(name, ‘蜗牛的React课程‘)
    })



    //删除功能
    it("只能ceo能删", async () => {
        await courseList.methods.createCourse(
            ‘蜗牛的Vue课程‘
        )
            .send({
                from: accounts[0],
                gas: ‘5000000‘
            })
        const address = await courseList.methods.getCourse().call()
        assert.equal(address.length, 2)

      await courseList.methods.removeCourse(0).send({
        from:accounts[9],
        gas:‘5000000‘
      })
      const address1 = await courseList.methods.getCourse().call()
      console.log(address1)
      assert.equal(address1.length,1)
      
    })

    it(‘判断是不是ceo‘,async ()=>{
        const isCeo1 = await courseList.methods.isCeo().call({
          from :accounts[9]
        })
        const isCeo2 = await courseList.methods.isCeo().call({
          from :accounts[1]
        })
        assert.ok(isCeo1)
        assert.ok(!isCeo2)
      })
      

})

6.完善课程的属性,添加其他属性

6.1 添加一下属性

课程: owner

课程创建者 name

课程名 content

课程简介 target

课程目标是募资多少 ETH

fundingPrice 众筹价格

price 上线价格

img 课程头图

video 视频

count 多少人支持

isOnline 是否上线

6.2 合约里添加Course以及createCourse完善
//Imooc.sol
function createCourse(string _name,string _content,uint _target,uint _fundingPrice,uint _price,string _img) public{
    address newCourse = new Course(ceo,msg.sender, _name, _content, _target, 				  	_fundingPrice, _price, _img);
    courses.push(newCourse);
  }
//Imooc.sol
contract Course{
  address public ceo;
  address public owner;
  string public name;
  string public content;
  uint public target;
  uint public fundingPrice;
  uint public price;
  string public img;
  string public video;
  bool public isOnline;
  uint public count;
  constructor(address _ceo, address _owner,string _name,string _content,uint _target,uint _fundingPrice,uint _price,string _img) public{
    ceo = _ceo;
    owner = _owner;
    name = _name;
    content = _content;
    target = _target;
    fundingPrice = _fundingPrice;
    price = _price;
    img = _img;
    video = ‘‘;
    count = 0;
    isOnline = false;
  }
        }
6.3 编写测试逻辑,完善属性
 it(‘测试添加课程‘, async () => {
        const oldaddress = await courseList.methods.getCourse().call()
        assert.equal(oldaddress.length, 0)
        await courseList.methods.createCourse(
            ‘蜗牛的React课程‘,
            "React+redux+reactrouter4开发招聘app",
            web3.utils.toWei(‘8‘),
            // 众筹价格
            web3.utils.toWei(‘2‘),
            web3.utils.toWei(‘4‘),
            "图片的hash"
        )
            .send({
                from: accounts[0],
                gas: ‘5000000‘
            })
        const address = await courseList.methods.getCourse().call()
        assert.equal(address.length, 1)

    })
    it("添加课程的属性", async () => {
        const [address] = await courseList.methods.getCourse().call()
        // 添加的课程合约的地址
        course = await new web3.eth.Contract(JSON.parse(Course.interface), address)
        const name = await course.methods.name().call()
        const content = await course.methods.content().call()
        const target = await course.methods.target().call()
        const fundingPrice = await course.methods.fundingPrice().call()
        const price = await course.methods.price().call()
        const img = await course.methods.img().call()
        const count = await course.methods.count().call()
        const isOnline = await course.methods.isOnline().call()
        assert.equal(name, ‘蜗牛的React课程‘)
        assert.equal(content, ‘React+redux+reactrouter4开发招聘app‘)
        assert.equal(target, web3.utils.toWei(‘8‘))
        assert.equal(fundingPrice, web3.utils.toWei(‘2‘))
        assert.equal(price, web3.utils.toWei(‘4‘))
        assert.equal(img, "图片的hash")
        assert.ok(!isOnline)
        assert.equal(count, 0)
    })

  it("只能ceo能删", async ()=>{
        await courseList.methods.createCourse(
          ‘蜗牛的Vue课程‘,
          ‘vue也是个好框架,简单好上手‘,
          web3.utils.toWei(‘8‘),
          // 众筹价格
          web3.utils.toWei(‘2‘),
          web3.utils.toWei(‘4‘),
          "图片的hash1"   
          )
              .send({
                from:accounts[0],
                gas:‘5000000‘
              })
        const address = await courseList.methods.getCourse().call()
        assert.equal(address.length,2)
    })

7.用户购买课程及课程上线

7.1 设置用户列表
    // 用户购买信息
  mapping(address=>uint) public users;
7.2 用户购买合约以及课程上线

课程上线之后众筹的钱立刻全部打给众筹者,之后再有用户购买,则进行分成。给ceo一成的利润。

// 众筹或者购买
  function buy() public payable{
    // 1. 用户没有购买过
    require(users[msg.sender]==0);
    if(isOnline){
      // 如果上线了 必须得用上线价格购买
      require(price == msg.value);
    }else{
      // 如果上线了 必须得用众筹价格购买
      require(fundingPrice == msg.value);
    }
    users[msg.sender] = msg.value;
    // 统计人数
    count += 1;
    
    if(target <= count*fundingPrice){
        // 钱超出目标
        if(isOnline){
          // 上线之后的购买
          uint value = msg.value;
          // 分成
          ceo.transfer(value/10);
          owner.transfer(value-value/10);
        }else{
          // 没上线 第一次超出
          isOnline = true;
          // 转账
          // 上线之前的钱,都在合约内部,众筹者是拿不到的
          owner.transfer(count*fundingPrice);

        }
    }
  }
7.3 用户获取课程详情
// 获取详情
  function getDetail() public view returns(string,string,uint,uint,uint,string,string,uint,bool,uint){
    uint role;
    if(owner==msg.sender){
      role = 0; //课程创建者
    }else if(users[msg.sender]>0){
      role = 1; // 已购买
    }else{
      role = 2; // 没买
    }
    return (
      name,
      content,
      target,
      fundingPrice,
      price,
      img,
      video,
      count,
      isOnline,
      role
    );
  }
7.4 上线之后众筹者才可以添加视频——ipfs地址
    function addVideo(string _video) public{
    require(msg.sender==owner);
    require(isOnline==true);
    video = _video;
  }
7.5编译通过

技术图片

8.课程购买测试编写

8.1 金钱转换

wei

finney

szabo

ether

1 ether == 10^3 finney
1 ether == 10^6 szabo
1 ether == 10^18 Wei
it(‘金钱转换‘,()=>{
    assert.equal(web3.utils.toWei(‘2‘),‘2000000000000000000‘)
  })
8.2 课程购买
      it(‘课程购买‘,async()=>{
        await course.methods.buy().send({
          from:accounts[2],
          value:web3.utils.toWei(‘2‘)
        })
        const value = await course.methods.users(accounts[2]).call()
        const count = await course.methods.count().call()
        assert.equal(value,web3.utils.toWei(‘2‘))
        assert.equal(count,1)

        // 输出value及users+
        console.log("钱是:")
        console.log(value)
        // console.log("uers是:")

        
        // 用户role的判断
        const detail = await course.methods.getDetail().call({from:accounts[0]})
        assert.equal(detail[9],0)
    
        // 课程
        console.log(detail)
        const detail2 = await course.methods.getDetail().call({from:accounts[2]})
        assert.equal(detail2[9],1)
    
        const detail3 = await course.methods.getDetail().call({from:accounts[5]})
        assert.equal(detail3[9],2)
      })

技术图片

8.3 引入bignumber.js

npm install bignumber.js

const BigNumber = require(‘bignumber.js‘)

8.4 还没上线的话,钱不入账
      it(‘还没上线,购买的课不入账‘,async()=>{
        const oldBlance = new BigNumber(await web3.eth.getBalance(accounts[0]))
        await course.methods.buy().send({
          from:accounts[3],
          value:web3.utils.toWei(‘2‘)
        })
        const newBlance = new BigNumber(await web3.eth.getBalance(accounts[0]))
        const diff = newBlance.minus(oldBlance)
        assert.equal(diff,0)
      })
8.5 还没上线的话,不能上传视频
it(‘还没上线,不能上传视频‘,async()=>{
    
        try{
          await course.methods.addVideo(‘video的hash‘)
                    .send({
                      from:accounts[0],
                      gas:‘5000000‘
                    })
          assert.ok(false)
        }catch(e){
            console.log(e)
          assert.equal(e.name,‘o‘)
        }
      })


8.6 不能重复购买
  it(‘不能重复购买‘,async()=>{
    try{
      await course.methods.buy().send({
        from:accounts[2],
        value:web3.utils.toWei(‘2‘)
      })
      assert.ok(false)

    }catch(e){
      console.log(e.name)
      assert.equal(e.name,‘RuntimeError‘)

    }

  })
8.7 课程必须是众筹价格
  it(‘课程必须是众筹价格‘,async()=>{
    try{
      await course.methods.buy().send({
        from:accounts[4],
        value:web3.utils.toWei(‘3‘)
      })
      assert.ok(false)

    }catch(e){
      assert.equal(e.name,‘RuntimeError‘)

    }

  })
8.8 众筹上线后,钱到账
  
  it(‘众筹上线后,钱到账‘,async()=>{
    const oldBlance = new BigNumber(await web3.eth.getBalance(accounts[0]))

    // 8 众筹家是2  买4次就上线
    await course.methods.buy().send({
      from:accounts[4],
      value:web3.utils.toWei(‘2‘)
    })
    await course.methods.buy().send({
      from:accounts[5],
      value:web3.utils.toWei(‘2‘)
    })
    const count = await course.methods.count().call()
    const isOnline = await course.methods.isOnline().call()
    assert.equal(count,4)
    assert.ok(isOnline)
    const newBlance = new BigNumber(await web3.eth.getBalance(accounts[0]))
    const diff = newBlance.minus(oldBlance)
    assert.equal(diff,web3.utils.toWei(‘8‘))
  })
8.9 课程必须是线上的价格
   it(‘课程必须是线上的价格‘,async()=>{
    try{
      await course.methods.buy().send({
        from:accounts[6],
        value:web3.utils.toWei(‘2‘)
      })
      assert.ok(false)

    }catch(e){
      assert.equal(e.name,‘RuntimeError‘)
    }

  })

 it(‘课程必须是线上的价格2‘,async()=>{
    // try{
      await course.methods.buy().send({
        from:accounts[6],
        value:web3.utils.toWei(‘4‘)
      })
      const count = await course.methods.count().call()
      assert.equal(count,5)

    // }catch(e){
    //   assert.equal(e.name,‘RuntimeError‘)
    // }
  })

8.10 上线之后购买 有分成收益
  it(‘上线之后购买 有分成收益‘,async()=>{
    // try{
      // ceo的约
    const oldCeoBlance = new BigNumber(await web3.eth.getBalance(accounts[9]))
    // 课程创建者
    const oldOwnerBlance = new BigNumber(await web3.eth.getBalance(accounts[0]))

      await course.methods.buy().send({
        from:accounts[7],
        value:web3.utils.toWei(‘4‘)
      })
      const newCeoBlance = new BigNumber(await web3.eth.getBalance(accounts[9]))
      const newOwnerBlance = new BigNumber(await web3.eth.getBalance(accounts[0]))

      const diffCeo = newCeoBlance.minus(oldCeoBlance)
      const diffOwner = newOwnerBlance.minus(oldOwnerBlance)
      assert.equal(diffCeo, web3.utils.toWei(‘0.4‘))
      assert.equal(diffOwner, web3.utils.toWei(‘3.6‘))
    // }catch(e){
    //   assert.equal(e.name,‘RuntimeError‘)
    // }
  })
8.11 上线之后,可以上传视频
it(‘上线之后,可以上传视频‘,async()=>{
    
      await course.methods.addVideo(‘video的hash‘)
                .send({
                  from:accounts[0],
                  gas:‘5000000‘
                })
      const video = await  course.methods.video().call()
      assert.equal(video,‘video的hash‘)
  })
8.12 完整测试代码
const path = require(‘path‘);
const assert = require(‘assert‘);
const Web3 = require(‘web3‘)
const ganache = require(‘ganache-cli‘)
const BigNumber = require(‘bignumber.js‘)
const web3 = new Web3(ganache.provider())
// 引入合约的json
const CourseList = require(path.resolve(__dirname, ‘../src/compiled/CourseList.json‘))
const Course = require(path.resolve(__dirname, ‘../src/compiled/Course.json‘))


// 定义几个全局变量,所有测试都需要
let accounts
// 实例
let courseList
let course

describe(‘测试课程的智能‘, () => {

    before(async () => {
        // 测试前的数据初始化
        accounts = await web3.eth.getAccounts()

        console.log(accounts)
        // 1. 虚拟部署一个合约
        courseList = await new web3.eth.Contract(JSON.parse(CourseList.interface))
            .deploy({ data: CourseList.bytecode })
            .send({
                // 最后一个是创建者——重点
                from: accounts[9],
                gas: ‘5000000‘
            })

    })

    it(‘合约部署成功‘, () => {
        assert.ok(courseList.options.address)
    })

    // it(‘测试添加课程‘, async () => {
    //     const oldaddress = await courseList.methods.getCourse().call()
    //     assert.equal(oldaddress.length, 0)
    //     await courseList.methods.createCourse(
    //         ‘蜗牛的React课程‘
    //     )
    //         .send({
    //             from: accounts[0],
    //             gas: ‘5000000‘
    //         })
    //     const address = await courseList.methods.getCourse().call()
    //     assert.equal(address.length, 1)
    //     console.log(address)

    // })

    // it("添加课程的属性", async () => {
    //     const [address] = await courseList.methods.getCourse().call()
    //     // 添加的课程合约的地址
    //     course = await new web3.eth.Contract(JSON.parse(Course.interface), address)
    //     const name = await course.methods.name().call()
    //     assert.equal(name, ‘蜗牛的React课程‘)
    // })
    it(‘测试添加课程‘, async () => {
        const oldaddress = await courseList.methods.getCourse().call()
        assert.equal(oldaddress.length, 0)
        await courseList.methods.createCourse(
            ‘蜗牛的React课程‘,
            "React+redux+reactrouter4开发招聘app",
            web3.utils.toWei(‘8‘),
            // 众筹价格
            web3.utils.toWei(‘2‘),
            web3.utils.toWei(‘4‘),
            "图片的hash"
        )
            .send({
                from: accounts[0],
                gas: ‘5000000‘
            })
        const address = await courseList.methods.getCourse().call()
        assert.equal(address.length, 1)

    })
    it("添加课程的属性", async () => {
        const [address] = await courseList.methods.getCourse().call()
        // 添加的课程合约的地址
        course = await new web3.eth.Contract(JSON.parse(Course.interface), address)
        const name = await course.methods.name().call()
        const content = await course.methods.content().call()
        const target = await course.methods.target().call()
        const fundingPrice = await course.methods.fundingPrice().call()
        const price = await course.methods.price().call()
        const img = await course.methods.img().call()
        const count = await course.methods.count().call()
        const isOnline = await course.methods.isOnline().call()
        assert.equal(name, ‘蜗牛的React课程‘)
        assert.equal(content, ‘React+redux+reactrouter4开发招聘app‘)
        assert.equal(target, web3.utils.toWei(‘8‘))
        assert.equal(fundingPrice, web3.utils.toWei(‘2‘))
        assert.equal(price, web3.utils.toWei(‘4‘))
        assert.equal(img, "图片的hash")
        assert.ok(!isOnline)
        assert.equal(count, 0)
    })


    //删除功能
    // it("只能ceo能删", async () => {
    //     await courseList.methods.createCourse(
    //         ‘蜗牛的Vue课程‘
    //     )
    //         .send({
    //             from: accounts[0],
    //             gas: ‘5000000‘
    //         })
    //     const address = await courseList.methods.getCourse().call()
    //     assert.equal(address.length, 2)

    //     await courseList.methods.removeCourse(0).send({
    //         from: accounts[9],
    //         gas: ‘5000000‘
    //     })
    //     const address1 = await courseList.methods.getCourse().call()
    //     console.log(address1)
    //     assert.equal(address1.length, 1)

    // })
    it("只能ceo能删", async ()=>{
        await courseList.methods.createCourse(
          ‘蜗牛的Vue课程‘,
          ‘vue也是个好框架,简单好上手‘,
          web3.utils.toWei(‘8‘),
          // 众筹价格
          web3.utils.toWei(‘2‘),
          web3.utils.toWei(‘4‘),
          "图片的hash1"   
          )
              .send({
                from:accounts[0],
                gas:‘5000000‘
              })
        const address = await courseList.methods.getCourse().call()
        assert.equal(address.length,2)
    })

    it(‘判断是不是ceo‘, async () => {
        const isCeo1 = await courseList.methods.isCeo().call({
            from: accounts[9]
        })
        const isCeo2 = await courseList.methods.isCeo().call({
            from: accounts[1]
        })
        assert.ok(isCeo1)
        assert.ok(!isCeo2)
    })

    it(‘金钱转换‘,()=>{
        assert.equal(web3.utils.toWei(‘2‘),‘2000000000000000000‘)
      })

      it(‘课程购买‘,async()=>{
        await course.methods.buy().send({
          from:accounts[2],
          value:web3.utils.toWei(‘2‘)
        })
        const value = await course.methods.users(accounts[2]).call()
        const count = await course.methods.count().call()
        assert.equal(value,web3.utils.toWei(‘2‘))
        assert.equal(count,1)

        // 输出value及users+
        console.log("钱是:")
        console.log(value)
        // console.log("uers是:")

        
        // 用户role的判断
        const detail = await course.methods.getDetail().call({from:accounts[0]})
        assert.equal(detail[9],0)
    
        // 课程
        console.log(detail)
        const detail2 = await course.methods.getDetail().call({from:accounts[2]})
        assert.equal(detail2[9],1)
    
        const detail3 = await course.methods.getDetail().call({from:accounts[5]})
        assert.equal(detail3[9],2)
      })

      it(‘还没上线,购买的课不入账‘,async()=>{
        const oldBlance = new BigNumber(await web3.eth.getBalance(accounts[0]))
        await course.methods.buy().send({
          from:accounts[3],
          value:web3.utils.toWei(‘2‘)
        })
        const newBlance = new BigNumber(await web3.eth.getBalance(accounts[0]))
        const diff = newBlance.minus(oldBlance)
        assert.equal(diff,0)
      })

      it(‘还没上线,不能上传视频‘,async()=>{
    
        try{
          await course.methods.addVideo(‘video的hash‘)
                    .send({
                      from:accounts[0],
                      gas:‘5000000‘
                    })
          assert.ok(false)
        }catch(e){
            console.log(e)
          assert.equal(e.name,‘o‘)
        }
      })
      it(‘不能重复购买‘,async()=>{
        try{
          await course.methods.buy().send({
            from:accounts[2],
            value:web3.utils.toWei(‘2‘)
          })
          assert.ok(false)
    
        }catch(e){
          console.log(e.name)
          assert.equal(e.name,‘RuntimeError‘)
    
        }
    
      })
      it(‘课程必须是众筹价格‘,async()=>{
        try{
          await course.methods.buy().send({
            from:accounts[4],
            value:web3.utils.toWei(‘3‘)
          })
          assert.ok(false)
    
        }catch(e){
          assert.equal(e.name,‘RuntimeError‘)
    
        }
    
      })
      
      it(‘众筹上线后,钱到账‘,async()=>{
        const oldBlance = new BigNumber(await web3.eth.getBalance(accounts[0]))
    
        // 8 众筹家是2  买4次就上线
        await course.methods.buy().send({
          from:accounts[4],
          value:web3.utils.toWei(‘2‘)
        })
        await course.methods.buy().send({
          from:accounts[5],
          value:web3.utils.toWei(‘2‘)
        })
        const count = await course.methods.count().call()
        const isOnline = await course.methods.isOnline().call()
        assert.equal(count,4)
        assert.ok(isOnline)
        const newBlance = new BigNumber(await web3.eth.getBalance(accounts[0]))
        const diff = newBlance.minus(oldBlance)
        assert.equal(diff,web3.utils.toWei(‘8‘))
      })
      it(‘课程必须是线上的价格‘,async()=>{
        try{
          await course.methods.buy().send({
            from:accounts[6],
            value:web3.utils.toWei(‘2‘)
          })
          assert.ok(false)
    
        }catch(e){
          assert.equal(e.name,‘RuntimeError‘)
        }
    
      })
      it(‘课程必须是线上的价格2‘,async()=>{
        // try{
          await course.methods.buy().send({
            from:accounts[6],
            value:web3.utils.toWei(‘4‘)
          })
          const count = await course.methods.count().call()
          assert.equal(count,5)
    
        // }catch(e){
        //   assert.equal(e.name,‘RuntimeError‘)
        // }
      })
      it(‘上线之后购买 有分成收益‘,async()=>{
        // try{
          // ceo的约
        const oldCeoBlance = new BigNumber(await web3.eth.getBalance(accounts[9]))
        // 课程创建者
        const oldOwnerBlance = new BigNumber(await web3.eth.getBalance(accounts[0]))
    
          await course.methods.buy().send({
            from:accounts[7],
            value:web3.utils.toWei(‘4‘)
          })
          const newCeoBlance = new BigNumber(await web3.eth.getBalance(accounts[9]))
          const newOwnerBlance = new BigNumber(await web3.eth.getBalance(accounts[0]))
    
          const diffCeo = newCeoBlance.minus(oldCeoBlance)
          const diffOwner = newOwnerBlance.minus(oldOwnerBlance)
          assert.equal(diffCeo, web3.utils.toWei(‘0.4‘))
          assert.equal(diffOwner, web3.utils.toWei(‘3.6‘))
        // }catch(e){
        //   assert.equal(e.name,‘RuntimeError‘)
        // }
      })
    
      it(‘上线之后,可以上传视频‘,async()=>{
        
          await course.methods.addVideo(‘video的hash‘)
                    .send({
                      from:accounts[0],
                      gas:‘5000000‘
                    })
          const video = await  course.methods.video().call()
          assert.equal(video,‘video的hash‘)
      })

})

END

以上是关于62solidity环境搭建编译及编写合约-3——2020年07月12日12:55:51的主要内容,如果未能解决你的问题,请参考以下文章

智能合约开发环境搭建及Hello World合约

solidity 智能合约(3):使用truffle编译部署及测试合约

智能合约从入门到精通:Solidity的特性与内部机制

智能合约从入门到精通:Solidity的特性与内部机制

区块链开发之Solidity智能合约开发

Web3与智能合约:开发一个简单的DApp并部署到以太坊测试网(Solidity+Hardhat+React)① 环境搭建