Unit Testing in Truffle

Welcome to the forum discussion for this section. Here you can ask questions or post feedback.

6 Likes

Owner Test Assignment
Testing the onlyOwner function modifier

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

contract("People", async function(accounts){
   it("shouldn't be possible to delete a person without being the contract owner", async function(){
        let instance = await People.deployed();
        await instance.createPerson("Dell", 30, 210, {value: web3.utils.toWei("1","ether"), from: accounts[2]});
        await truffleAssert.fails(instance.deletePerson(accounts[2], {from: accounts[1]}), truffleAssert.ErrorType.REVERT);
    });
    it("should be possible to delete a persen by the contract owner", async function(){
        let instance = await People.deployed();
        //await instance.createPerson("Dell", 30, 210, {value: web3.utils.toWei("1","ether"), from: accounts[2]});
        await instance.deletePerson(accounts[2], {from: accounts[0]});
        const {0: Name, 1: Age, 2: Height, 3: Senior} = await instance.getPerson({from: accounts[2]});
        assert(Name === "" && Age == 0, "Person not deleted");
    });
});
2 Likes

Value Assignment
There are better solutions for sure but for now i’m satisfied with it. I have learned quite a lot by solving those two assignments. :crazy_face:

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

contract("People", async function(accounts){
    it("should increase the balance of the contract address correctly after createPerson", async function(){
        let instance = await People.deployed();
        let Balance = await web3.eth.getBalance(People.address);
        await instance.createPerson("Moneyman", 44, 178, {value: web3.utils.toWei("1","ether"), from: accounts[1]});
        let newBalance = await web3.eth.getBalance(People.address);
        assert(newBalance == parseInt(Balance) + parseInt(web3.utils.toWei("1","ether")), "Did not transfer the estimated funds");        
    });
    it("shouldn't be possible to withdraw contract funds exept for the contract owner", async function(){
        let instance = await People.deployed();
        await truffleAssert.fails(instance.withdrawAll({from: accounts[1]}));
    });
    it("shoud be possible to withdraw contract funds just for the contract owner", async function(){
        let instance = await People.deployed();
        await truffleAssert.passes(instance.withdrawAll({from: accounts[0]}));
    });

});
1 Like

it(“when createPerson() called, owner balance increases”, async function(){
let balance = await web3.eth.getBalance(People.address);
await instance.createPerson(“Sarrah”, 35, 162, {value: web3.utils.toWei(“1”,“ether”), from: accounts[1]});
let newBalance = await web3.eth.getBalance(People.address);
assert(newBalance > balance, “transfer failed”);
});

it(“only owner should be able to withdraw funds”, async function(){
await instance.createPerson(“Sarrah”, 35, 162, {value: web3.utils.toWei(“1”,“ether”), from: accounts[1]});
await truffleAssert.fails(instance.withdrawAll({from: accounts[1]}),truffleAssert.ErrorType.REVERT);
});

it(“Balance should be zero”, async function(){
await instance.createPerson(“Sarrah”, 35, 162, {value: web3.utils.toWei(“1”,“ether”), from: accounts[1]});
await instance.withdrawAll({from: accounts[0]});
let finalBalance = await web3.eth.getBalance(People.address);
assert(parseInt(finalBalance) === 0, “Balance should be zero”);
});

3 Likes

Great, I’m happy to hear that. Good job!

1 Like

Owner Test Assignment:

My first response to the assignment was incorrect as it used truffleAssert.fails instead of truffleAssert.passes to test the owner’s ability to delete people. It also did not test non-owners… :disappointed_relieved:

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

contract("People", async (accounts) => {
/*it("should confirm the contract owner", async () => {
   let instance = await People.deployed();
   let owner = await instance.owner();
   assert(owner === accounts[0], "Owner is not set correctly");
 });*/
it("should not allow non-owner to delete people", async () => {
    let instance = await People.deployed();
    await instance.createPerson("Lisa", 45, 155, {from: accounts[1], value: web3.utils.toWei("1", "ether")});
    await truffleAssert.fails(instance.deletePerson(accounts[1], {from: accounts[1]}), truffleAssert.ErrorType.REVERT);
  });
  it("should allow the owner to delete people", async () => {
    let instance = await People.deployed();
    await truffleAssert.passes(
      instance.deletePerson(
        accounts[1],
        {from: accounts[0]}),
        truffleAssert.ErrorType.REVERT);
  });
});
2 Likes

Value assignment:

I’m not very confident in the first test on the list. It works as written, however, it fails when I use the address string I found for the contract on Ganache. Unsure if I’m using the correct source fro each address.

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

contract("People", async (accounts) => {

  let instance;

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

  it("should match the balance on the contract with the balance on the blockchain", async () => {
    let contractBalance = await instance.balance();
    let onChainBalance = await web3.eth.getBalance(People.address);
    assert(parseInt(contractBalance) === parseInt(onChainBalance));
  });

  it("should allow owner to withdraw", async () => {
    await truffleAssert.passes(instance.withdrawAll({from: accounts[0]}));
  });

  it("should not allow non-owner to withdraw", async () => {
    await truffleAssert.fails(instance.withdrawAll({from: accounts[1]}));
  });

  it("should reduce balance after withdrawal", async () => {
    await instance.createPerson("Joey", 35, 180, {from: accounts[2], value: web3.utils.toWei("1", "ether")});
    let balance = await instance.balance();
    await instance.withdrawAll({from: accounts[0]});
    let newBalance = await instance.balance();
    assert(parseInt(newBalance) === 0);
  });

  it("should increase the owner's balance", async () => {
    let instance = await People.new();
    let ownerBalance = await web3.eth.getBalance('0xef532B610CCC9DffDe4Bbadb0810e09641281b2B');
    await instance.createPerson("Joey", 35, 180, {from: accounts[2], value: web3.utils.toWei("1", "ether")});
    await instance.withdrawAll({from: accounts[0]});
    assert(ownerBalance += parseInt(web3.utils.toWei("1", "ether")));
  });

  it("should increase the balance when a new person is created", async () => {
    let instance = await People.new();
    await instance.createPerson("Joey", 35, 180, {from: accounts[2], value: web3.utils.toWei("1", "ether")});
    let balance = await instance.balance();
    assert(parseInt(balance) === parseInt(web3.utils.toWei('1', 'ether')));
  });
});

Look correct to me! Good job dude!

1 Like

Hi @filip. Can you look over this and see if I have thought correctly?
It passed the test, but I’m still unsure if it`s correct and if anything is missing?

I’ve only tested the deletePerson () function now, but am I supposed to do a test for withdrawAll () as well?

This is my solution.

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

contract("People", async function(accounts) {
   it("Shouldn`t create a person with age above 150 years.", async function() {
       let instance = await People.deployed();
       await truffleAssert.fails(instance.createPerson("Ivo", 155, 183, {value: web3.utils.toWei("1", "ether")}), truffleAssert.ErrorType.REVERT);
   });
   it("Shouldn`t create a person without payment.", async function() {
       let instance = await People.deployed();
       await truffleAssert.fails(instance.createPerson("Lene", 39, 183, {value: 10000}), truffleAssert.ErrorType.REVERT);
   });
   it("Should set senior status correctly.", async function() {
       let instance = await People.deployed();
       await instance.createPerson("Ivo", 65, 183, {value: web3.utils.toWei("1", "ether")});
       let result = await instance.getPerson();
        assert(result.senior === true, "Senior level not set.");
   });
   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.");
   });
   it("Shouldn`t be deleted by anybody but the owner of the contract", async function() {
       let instance = await People.deployed();
       await instance.createPerson("Samuel", 17, 187, {value: web3.utils.toWei("1", "ether")});
       await truffleAssert.fails(instance.deletePerson(accounts[0], {from: accounts[1]}), truffleAssert.ErrorType.REVERT);
   });
   it("Should be deleted by only the Owner of the contract.", async function() {
       let instance = await People.deployed();
       await instance.deletePerson(accounts[0]);
       let result = await instance.getPerson();
       assert(result.age.toNumber() ===  0, "Person not deleted by Owner.");
   })
});
1 Like

Awesome! Thanks man!

Hi Filip,
I am only on the first video of this section (so maybe it will be done later) but is there any reason for not having a migration file for the Owner contract (it is not deployed on the Ganache)?

1 Like

Hi @filip,
I do not know why my “set age” test did not pass, can you please take a look?
image

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

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);
    });
    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);
    });
    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");
    });
    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");
    })

Thank you very much!

Hello @Golden_Pig_Coin,
I would guess that there is a issue with the type of the values but unfortunetly I can not expain it in detail why it behaves like this. But here are 2 potential solutions for you:

assert(result.age == 65, "Age not set correctly");
assert(parseInt.result.age === 65, "Age not set correctly");

Something to read about Comparison operators.

I hope this can help you.

1 Like

Hi @Paultier,
thank you very much again for your help!
yes, I changed the code to result.age == 65
now it works!

1 Like

Looks good. I would say it covers our contract pretty good :slight_smile: Great job!

Do you mean the contract that we inherit? If we inherit a contract, it will be imported by the compiler into the same file and deployed at the same time as the parent contract. So no need to deploy that.

Hi @filip,

here is a test I wrote to test that the owner’s balance would decrease after creating a new person, because the owner has to spend 1 Ether to do that, but it does not seem to work, can you please take a look at it? Thank you very much!

contract ("People", async function(accounts){
  let instance;
  before (async function(){
    instance = await People.deployed()
  });   
 it("should decrease owner's balance after adding people", async function(){
      let instance = await People.new();
      let initialBalance = parseInt(await web3.eth.getBalance(accounts[0]));
      await instance.createPerson("David", 38, 175,{from: accounts[1], value: web3.utils.toWei("1", "ether")});
      let newBalance = parseInt(await web3.eth.getBalance(accounts[0]));
      assert(newBalance < initialBalance, "owner's balance did not decrease");
    });
 });

Hey @Golden_Pig_Coin,
I’m not quite sure if I get your question correctly but one thing I can see is, that according to your test, Account[1] is spending 1 Ether to create a person. I think it supposed to be Account[0] like from what you make the balance check?

2 Likes

I think that’s the issue, yes. I’m so happy to see that you are helping each other :slight_smile:

2 Likes

Hi @Paultier
thank you very much! You are right, I changed to account[0] which created the person, and now it works!

2 Likes