Unit Testing in Truffle

Hi @JRB
As we can see in your test, the user creation is not failing. It means your require is not working in the createPerson method. Are you checking the age submitted in your smart contract ?
If yes can you share this function code with us ?
Thx

2 Likes

Hi @kiddey

There is a typo in your first test:

await instance.createPerson(ā€œDaveā€, 80, 140, {value: web3.utils.toWei(ā€œ1ā€, ā€œetherā€), from accounts[1]});

Should be

await instance.createPerson(ā€œDaveā€, 80, 140, {value: web3.utils.toWei(ā€œ1ā€, ā€œetherā€), from: accounts[1]});

How do you make your second test working ? Where is you instance declared ? You are using the deletePerson method on instance but i this you should add

 let instance = await People.deployed();

At the beginning of your test 2, 4 and 5. Did you use a ā€œBeforeEachā€ function at the beginning of your test file ?

1 Like

Hi @ToMMaaY

Your tests are correct, but it is better to test your functionalities one by one before testing multiples functions in one test. As you are using ā€œbeforeEachā€ People.deployed you can split your first test into 2 tests. Your first test is called ā€œshould be able to delete personā€ but it could fail creating one ,so it will be a bit confusing for someone else running your test if the error come from createPerson.

2 Likes

Hi, here are my tests for checking the balance:

  it("Balances should be matching after creating a person", async function() {
    let instance = await People.new();
    await instance.createPerson("Brook", 65, 280, {from: accounts[1], value: web3.utils.toWei("1", "ether")});
    let expectedBalance = await instance.balance();
    let actualBalance = await web3.eth.getBalance(instance.address);
    assert.equal(actualBalance, expectedBalance);
  });
  it("Owner is able to withdraw", async function() {
    await instance.createPerson("Brook", 65, 280, {value: web3.utils.toWei("1",'ether')});
    await truffleAssert.passes(instance.withdrawAll({from: accounts[0]}),"Owner can't withdraw");
  });
  it("Owner should be able to withdraw balance and the balance should be 0", async function() {
    let instance = await People.new();
    await instance.withdrawAll();
    let expectedBalance = await instance.balance();
    let actualBalance = await web3.eth.getBalance(instance.address);
    assert.equal(actualBalance, expectedBalance);
  });
1 Like

Hi @gabba!
Here is the create person function code.

function createPerson(string memory name, uint age, uint height) public payable costs(1 ether){
      require(age > 200, "Age needs to be below 200");
      require(msg.value >= 1 ether);
      balance += msg.value;

I have swiched the require age from 150 to 200, and then the age test passed. However the senior test still fails. Allso please tell me if I wassenā€™t supossed to change the require statment.

Here is the people.sol contract if you need more information.

import "./Ownable.sol";
pragma solidity 0.5.12;

contract People is Ownable{

    struct Person {
      uint id;
      string name;
      uint age;
      uint height;
      bool senior;
    }

    event personCreated(string name, bool senior);
    event personDeleted(string name, bool senior, address deletedBy);

    uint public balance;

    modifier costs(uint cost){
        require(msg.value >= cost);
        _;
    }

    mapping (address => Person) private people;
    address[] private creators;

    function createPerson(string memory name, uint age, uint height) public payable costs(1 ether){
      require(age > 200, "Age needs to be below 150");
      require(msg.value >= 1 ether);
      balance += msg.value;

        //This creates a person
        Person memory newPerson;
        newPerson.name = name;
        newPerson.age = age;
        newPerson.height = height;

        if(age >= 65){
           newPerson.senior = true;
       }
       else{
           newPerson.senior = false;
       }

        insertPerson(newPerson);
        creators.push(msg.sender);

        assert(
            keccak256(
                abi.encodePacked(
                    people[msg.sender].name,
                    people[msg.sender].age,
                    people[msg.sender].height,
                    people[msg.sender].senior
                )
            )
            ==
            keccak256(
                abi.encodePacked(
                    newPerson.name,
                    newPerson.age,
                    newPerson.height,
                    newPerson.senior
                )
            )
        );
        emit personCreated(newPerson.name, newPerson.senior);
    }
    function insertPerson(Person memory newPerson) private {
        address creator = msg.sender;
        people[creator] = newPerson;
    }
    function getPerson() public view returns(string memory name, uint age, uint height, bool senior){
        address creator = msg.sender;
        return (people[creator].name, people[creator].age, people[creator].height, people[creator].senior);
    }
    function deletePerson(address creator) public onlyOwner {
      string memory name = people[creator].name;
      bool senior = people[creator].senior;

       delete people[creator];
       assert(people[creator].age == 0);
       emit personDeleted(name, senior, owner);
   }
   function getCreator(uint index) public view onlyOwner returns(address){
       return creators[index];
   }
   function withdrawAll() public onlyOwner returns(uint) {
       uint toTransfer = balance;
       balance = 0;
       msg.sender.transfer(toTransfer);
       return toTransfer;
   }

}

Owner Test Assignment
Unit Testing

const People = artifacts.require("People");
const truffleAssert = require("truffle-assertions");


contract( "People", async function( accounts){

  it("should not allow  a non-creator/owner of the person entry to delete the person", async function(){
    let instance = await People.deployed();
    await instance.createPerson( "Rossi", 22, 160, { value: web3.utils.toWei("1", "ether"), from: accounts[3] });
    await truffleAssert.fails( instance.deletePerson( accounts[3], { from: accounts[3]} ), truffleAssert.ErrorType.REVERT);
  });
  
  it("should allow the creator/owner of the person entry to delete the person", async function(){
    let instance = await People.deployed();
    await instance.createPerson( "Valentino", 39, 160, { value: web3.utils.toWei("1", "ether"), from: accounts[2] });
    await truffleAssert.passes( instance.deletePerson( accounts[2], { from: accounts[0]}));
  });
  
});

Edited by @gabba: please use the Preformatted text tag t post code @ibin :wink:

1 Like

Those of you getting the peopleproject migration error from starting a new project need to go into their js config in the new folder, remove the comment for the sol version, and add 0.5.12 like in the first few videos. I am sure most of you already figured this out.

1 Like

Hi @JRB

Your require should check if the age is inferior to 200 and not superior to 200.

require(age < 150, "Age needs to be below 150");

You are using the wrong operator <

So i think you are not creating a new user and at the end the value of newPerson.senior is false because the default value of a boolean if itā€™s not set is false.
Using the correct require should solve you issue

1 Like

Thanks. It finlaly worked. Thank you so much for your help!

Here is my code:

it ("should delete user if you are onlyOwner", async function(){
  let instance = await People.deployed();
  await instance.createPerson("June", 65, 190, {value: web3.utils.toWei("1", "ether")});
  await truffleAssert.passes(instance.deletePerson(accounts[1], {from: accounts[0]}), truffleAssert.ErrorType.REVERT);
  let result = await instance.getPerson();
});

it ("should not delete user if you are not onlyOwner", async function(){
  let instance = await People.deployed();
  await instance.createPerson("June", 65, 190, {value: web3.utils.toWei("1", "ether")});
  await truffleAssert.fails(instance.deletePerson(accounts[2], {from: accounts[1]}), truffleAssert.ErrorType.REVERT);
  let result = await instance.getPerson();
})

Edit by gabba: plz use the preformatted text tag thx you @DeCryptolorian

1 Like

More answers - I was so close without parseFloatā€¦

it ("balance should increase when a person is added", async function(){
let instance = await People.new();
await truffleAssert.passes(instance.createPerson("Jim", 20, 190, {value: web3.utils.toWei("1", "ether")}), truffleAssert.ErrorType.REVERT);
let c_balance = await instance.balance();
let a_balance = await web3.eth.getBalance(instance.address);
assert(c_balance == a_balance);
});

it ("balance cannot be withdrawn by another", async function(){
  let instance = await People.new();
  await truffleAssert.passes(instance.createPerson("Blue", 20, 190, {from: accounts[2], value: web3.utils.toWei("1", "ether")}), truffleAssert.ErrorType.REVERT);
  await truffleAssert.fails(instance.withdrawAll({from: accounts[2]}), truffleAssert.ErrorType.REVERT);
});

it ("balance can be withdrawn by onlyOwner", async function(){
  let instance = await People.new();
  await truffleAssert.passes(instance.createPerson("Green", 20, 190, {from: accounts[2], value: web3.utils.toWei("1", "ether")}), truffleAssert.ErrorType.REVERT);
  await instance.withdrawAll({from: accounts[0]});
});

it ("balance increases for onlyOwner and contract balance is 0", async function(){
  let instance = await People.new();
  await instance.createPerson("Lisa", 35, 160, {from: accounts[2], value: web3.utils.toWei("1", "ether")});
  let o_before_balance = parseFloat(await web3.eth.getBalance(accounts[0]));
  await instance.withdrawAll();
  let o_after_balance = parseFloat(await web3.eth.getBalance(accounts[0]));
  assert(o_before_balance < o_after_balance, "Owners balance was updated");
});

Edit by gabba: plz use the preformatted text tag thx you @DeCryptolorian

const People = artifacts.require("People");
const truffleAssert = require('truffle-assertions');

contract("People", async accounts => {
  it('should not allow non-owner deletions', async () => {
    const instance = await People.deployed();
    truffleAssert.fails(
      instance.deletePerson(accounts[0], { from: accounts[1] }),
      truffleAssert.ErrorType.REVERT
    );
  });

  it('should allow owner to delete', async () => {
    const instance = await People.deployed();
    truffleAssert.passes(instance.deletePerson(accounts[0], { from: accounts[0] }));
  });
});

1 Like
const People = artifacts.require("People");
const truffleAssert = require('truffle-assertions');

contract("People", async accounts => {
  let instance;
  beforeEach(async () => {
    instance = await People.new();
  });

  it('should have correct balance after creating a person and owner withdraws', async () => {
    await instance.createPerson('Bob', 65, 4, { value: web3.utils.toWei('1.5', 'ether') });
    let internalBalance = await instance.balance();
    let actualBalance = web3.utils.toBN(await web3.eth.getBalance(instance.address));
    assert.deepEqual(internalBalance, actualBalance);
    assert.deepEqual(web3.utils.toBN(web3.utils.toWei('1.5', 'ether')), actualBalance);

    await instance.withdrawAll();
    internalBalance = await instance.balance();
    actualBalance = web3.utils.toBN(await web3.eth.getBalance(instance.address));
    assert.deepEqual(internalBalance, actualBalance);
    assert.deepEqual(web3.utils.toBN(web3.utils.toWei('0', 'ether')), actualBalance);
  });
});

1 Like
const People = artifacts.require("People");
const truffleAssert = require("truffle-assertions");

contract("People", async function(accounts) {
  it("Should remove person if deletePerson is executed by owner", async function(){
    let instance = await People.deployed();
    let ownerAddress = accounts[0];
    await instance.createPerson("Bob", 65, 190, {value: web3.utils.toWei("1", "ether")});
    instance.deletePerson(ownerAddress);
    let result = await instance.getPerson();
    assert(result.age.toNumber() == 0, "Person not correctly deleted");
  });
  it("Shouldn't remove person if deletePerson not executed by owner", async function(){
    let instance = await People.deployed();
    let ownerAddress = accounts[0];
    let notOwnerAddress = accounts[1];
    await instance.createPerson("Bob", 65, 190, {value: web3.utils.toWei("1", "ether")});
    await truffleAssert.fails(instance.deletePerson(ownerAddress, {from: notOwnerAddress}), truffleAssert.ErrorType.REVERT);
  });
});

1 Like
const People = artifacts.require("People");
const truffleAssert = require("truffle-assertions");

contract("People", async function(accounts) {

  let instance;
  //run before all tests
  before(async function(){
    instance = await People.deployed();
  });

  it("Should increase balance by 1 ether when creating a person", async function(){
    let contractAddress = instance.address;
    let notOwnerAddress = accounts[3];
    let initialBalance = await web3.eth.getBalance(contractAddress)
    await instance.createPerson("Bob", 65, 190, {value: web3.utils.toWei("1", "ether"), from: notOwnerAddress});
    let finalBalance = await web3.eth.getBalance(contractAddress)
    assert((finalBalance - initialBalance) == web3.utils.toWei("1", "ether"));
  });
  it("Shouldn't allow withdraw to non owner", async function(){
    let contractAddress = instance.address;
    let notOwnerAddress = accounts[3];
    await truffleAssert.fails(instance.withdrawAll({from: notOwnerAddress}), truffleAssert.ErrorType.REVERT);
  });
  it("Should allow withdraw to owner", async function(){
    await truffleAssert.passes(instance.withdrawAll());
  });
  it("Should hold zero balance after withdraw", async function(){
    let contractAddress = instance.address;
    let ownerAddress = accounts[0];
    let notOwnerAddress = accounts[3];

    await instance.createPerson("Bob", 65, 190, {value: web3.utils.toWei("1", "ether"), from: notOwnerAddress});
    let contractAddressBalance = await web3.eth.getBalance(contractAddress);
    let contractInitialBalance = contractAddressBalance;
    console.log("contractAddressBalance: ", contractAddressBalance);
    assert(contractAddressBalance > 0, "Contract balance should be greater than zero");

    await instance.withdrawAll();
    let floatBalance = await instance.balance();
    let contractBalance = parseFloat(floatBalance);
    contractAddressBalance = await web3.eth.getBalance(contractAddress);
    assert(contractBalance == 0, "Contract instance balance is not zero after withdraw");
    assert(contractAddressBalance == 0, "Contract address balance is not zero after withdraw");
  });
  it("Should transfer balance to owner", async function(){
    let contractAddress = instance.address;
    let ownerAddress = accounts[0];
    let notOwnerAddress = accounts[3];
    let ownerAddressBalance = await web3.eth.getBalance(ownerAddress);
    let ownerAddressInitialBalance = ownerAddressBalance;
    console.log("Contract owner balance is: ", ownerAddressBalance);

    const txReceipt = await instance.createPerson("Bob", 65, 190, {value: web3.utils.toWei("1", "ether"), from: notOwnerAddress});
    const gasFee = txReceipt.receipt.gasUsed;
    console.log("gasFee: ", gasFee);
    let contractBalance = await web3.eth.getBalance(contractAddress);
    let contractInitialBalance = contractBalance;
    console.log("contractBalance: ", contractBalance);
    assert(contractBalance > 0, "Contract balance should be greater than zero");

    await instance.withdrawAll();

    ownerAddressBalance = await web3.eth.getBalance(ownerAddress);
    console.log("Contract owner balance is: ", ownerAddressBalance);
    assert(ownerAddressBalance >  ownerAddressInitialBalance, "Ower funds are not correct after withdraw.");
    //console.log(ownerAddressInitialBalance + contractInitialBalance - gasFee);
    //assert(ownerAddressBalance == (ownerAddressInitialBalance + contractInitialBalance - gasFee), "Owner funds are not correct after withdraw.");
  });
});

1 Like

Hey @filip, @gabba!
In the Owner Test Asinment I have the test that makes sure that if a user is not owner of a person and atempts to delet that person it will fail, that test is allmost complete. However I have one problem that I just canā€™t figure out. When I run the test the following errer occures:


As you can see, it explains that accounts is not difined.
As much as I tried I canā€™t seem to fix this problem.

Here is the peopletest.js file.

const People = artifacts.require("People");
const truffleAssert = require("truffle-assertions");

// This test makes shore that a person isent created with an age of over 150 years
contract("People", async function(){
    it("Shouldn't create a person with age over 150 years", async function(){
        let instance = await People.deployed();
        await truffleAssert.fails(instance.createPerson("Bob", 200, 190, {value: web3.utils.toWei("1", "ether")}), truffleAssert.ErrorType.REVERT);
    });

// This test makes shore that a person isent ceated without payment
      it("shouldn't create a person without payment", async function(){
        let instance = await People.deployed();
        await truffleAssert.fails(instance.createPerson("Bob", 50, 190, {value: 1000}), truffleAssert.ErrorType.REVERT);
  });

// This test makes shore that the senior of a person is set correctly
  it("should set senior status correctly", async function(){
        let instance = await People.deployed();
        await instance.createPerson("Bob", 65, 190, {value: web3.utils.toWei("1", "ether")});
        let result = await instance.getPerson();
        assert(result.senior === true, "Senior level not set");
  });

// This test makes shore that the age of a person is set correctly
  it("Should set age correctly", async function(){
      let instance = await People.deployed();
      let result = await instance.getPerson();
      assert(result.age.toNumber() === 65, "Age not set correctly");
  });

// This test makes shore that only the owner of a person can delete his person
  it("Delete Unseccesfull,  User is not owner of person.", async function(){
    let instance = await People.deployed();
    await instance.createPerson("Timmy Fias", 65, 6, {value: web3.utils.toWei("1", "ether")});
    await truffleAssert.fails(instance.deletePerson(accounts[0], {from: accounts[1]}), truffleAssert.ErrorType.REVERT);
  });
});

Let me know if you need any more information.
Thanks!

Hey @DeCryptolorian!
If you use preformated text to show your code than it will be easier to read. As is, reading your code is sort of dificult to understand.
prefromatted_text-animated

1 Like

onlyOwner Test:

contract("People", async (accounts) => {
	let instance;

	beforeEach(async () => {
		instance = await People.deployed();
	})


	it("should delete person when you're owner", async () =>  {
		await instance.deletePerson(accounts[0], { from: accounts[0]} )

		let result = await instance.getPerson();
		assert(result.age.toNumber() === 0, "Person not deleted")
	})

	it("shouldn't delete when you're not owner", async () => {
		await truffleAssert.fails(instance.deletePerson(accounts[0], {from: accounts[1]}), truffleAssert.ErrorType.REVERT)
	})
})

Never mind. I remembered that I can define something in the peramiters of a function.

That test passed.
On to the next one!

Here is my solotion for the Owner Test Asinment.

it("should set senior status correctly", async function(){
        let instance = await People.deployed();
        await instance.createPerson("Bob", 65, 190, {value: web3.utils.toWei("1", "ether")});
        let result = await instance.getPerson();
        assert(result.senior === true, "Senior level not set");
  });

// This test makes shore that only the owner of a person can delete his person
  it("Delete Unseccesfull,  User is not owner of person.", async function(){
    let instance = await People.deployed();
    await truffleAssert.fails(instance.deletePerson(accounts[0], {from: accounts[1]}), truffleAssert.ErrorType.REVERT);
  });

// This test makes shore that the owner can delet his person.
  it("Should let owner of person delet his person", async function(){
    let instance = await People.deployed();
    await (instance.deletePerson(accounts[0], {from: accounts[0]}));
  });
});