Unit Testing in Truffle

It wasn’t very clear to me the difference between before, beforeEach, after and afterEach functions.

What I understood is before() runs just once before the following test is executed; after() runs once after the following test. The other two run before/after each existing test in the file.

Is that correct?

1 Like

Hey @alegarap

What I understood is before() runs just once before the following test is executed; after() runs once after the following test. The other two run before/after each existing test in the file.

That is correct :slight_smile:

Cheers,
Dani

2 Likes

//This took a while. I had to reinstall Truffle and Ganache to get it working. :rage:

it(“should not allow non-owner to delete Punters”, async function(){
let instance = await Punters.deployed();
await instance.createPerson(“Liz”, 35, 160, {from: accounts[2], value: web3.utils.toWei(“1”, “ether”)});
await truffleAssert.fails(instance.deletePerson(accounts[2], {from: accounts[2]}), truffleAssert.ErrorType.REVERT);
});
it(“should allow the owner to delete Punters”, async function(){
let instance = await Punters.new();
await instance.createPerson(“Liz”, 35, 160, {from: accounts[2], value: web3.utils.toWei(“1”, “ether”)});
await truffleAssert.passes(instance.deletePerson(accounts[1], {from: accounts[0]}));
});

@filip

when I run a test in the console I get the following error

TypeError [ERR_INVALID_REPL_INPUT]: Listeners for uncaughtException cannot be used in the REPL

Any thoughts?

const People = artifacts.require("People");

const AssertionError = require("assertion-error");

const truffleAssert = require("truffle-assertions");

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

  it("Should not create a person older than 150 years", async function () {

    let instance = await People.deployed();

    await truffleAssert.fails(

      instance.createPerson("Nico", 1000, 180, {

        value: web3.utils.toWei("1", "ether"),

      }),

      truffleAssert.ErrorType.REVERT

    );

  });

  it("Should not create a without payment", async function () {

    let instance = await People.deployed();

    await truffleAssert.fails(

      instance.createPerson("Nico", 50, 180, {

        value: 1000,

      }),

      truffleAssert.ErrorType.REVERT

    );

  });

  it("Should set senior status correctly", async function () {

    let instance = await People.deployed();

    await instance.createPerson("Nico", 90, 180, {

      value: web3.utils.toWei("1", "ether"),

    });

    let result = await instance.getPerson();

    assert(result.senior === true, "Senior level not set");

  });

  it("Should not be execute by anyone but the owner", async function () {

    let instance = await People.deployed();

    await truffleAssert.fails(

      instance.deletePerson(accounts[0], { from: accounts[3] }),

      truffleAssert.ErrorType.REVERT

    );

  });

  it("Should allow the owner to delete people", async function () {

    let instance = await People.deployed();

    let resultBeforeDelete = await instance.getPerson();

    await instance.deletePerson(accounts[0]);

    let resultAfterDelete = await instance.getPerson();

    assert(

      resultBeforeDelete !== resultAfterDelete,

      "The person was not deleted"

    );

  });

});
1 Like

Hey @KingArt,

That looks like an issue with node, check this faq: FAQ - How to downgrade Node.Js

Cheers,
Dani

1 Like

Thanks Dani that worked!

1 Like

Owner test:

it(“shouldn’t be possable for nonowner to delete person”, async function(){
let instance = await People.deployed();
await instance.createPerson(“Mislav4”, 100, 196, {value : web3.utils.toWei(“1”, “ether”), from:accounts[1]});
await truffleAssert.fails(instance.deletePerson(accounts[1],{from:accounts[1]}))

});
it(“should be possible for owner to delete”, async function(){
let instance = await People.deployed();
assert(instance.deletePerson(accounts[0]));
});

1 Like

Value Assignment

it(“balance should increase when adding a person”, async function(){
let instance = await People.deployed();
start = await web3.eth.getBalance(People.address);
await instance.createPerson(“Mislav5”, 100, 196, {value : web3.utils.toWei(“1”, “ether”), from:accounts[1]});
end = await web3.eth.getBalance(People.address);
assert(parseInt(end) === parseInt(start) + 1000000000000000000);
});
it(“owner should be able to withdraw and balance should be zero”, async function(){
let instance = await People.deployed();
assert(await instance.withdrawAll({from:accounts[0]}));
balance = await web3.eth.getBalance(People.address)
assert(parseInt(balance)===0, “Balance not zero :” + balance);
});

1 Like
  it("should get creator if called by the owner", async () => {
    const instance = await People.deployed();
    await instance.createPerson('Bob', 70, 150, {value: web3.utils.toWei("1", "ether")});
    const creator = await instance.getCreator(0);
    assert(creator === accounts[0]);
  })

  it("should not delete person if called not by the owner", async () => {
    const instance = await People.deployed();
    await instance.createPerson('Bob', 70, 150, {value: web3.utils.toWei("1", "ether")});
    // Account 1 tries to delete the person created by the owner
    await truffleAssert.fails(instance.deletePerson(accounts[0], {from: accounts[1]}), truffleAssert.ErrorType.REVERT);
  })
1 Like

Value Assignment

const truffleAssert = require("truffle-assertions");

const People = artifacts.require("People");

const getContractBalance = async (address) => {
  const balanceWei = await web3.eth.getBalance(address);

  return web3.utils.fromWei(balanceWei, "ether");
};

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

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

  it("should reflect correct balance", async () => {
    const COSTS_ETHER = "15";

    await instance.createPerson('Bob', 70, 150, {value: web3.utils.toWei(COSTS_ETHER, "ether")});
    const contractBalance = await getContractBalance(instance.address);
  
    assert(contractBalance === COSTS_ETHER);
  });
  
  it("owner should withdraw all", async () => {
    await instance.withdrawAll();
    const contractBalanceWei = await web3.eth.getBalance(instance.address);
    assert(contractBalanceWei === "0");
  })
});
1 Like

It seems partial working but the following i do not understand.
when i use account[0] for creating and deleting it seems to work but changing all to account[1] which schould result in same result it fails ???
what am i missing ?

it(“Only owner can delete … test”, async function(){
let instance = await People.deployed();
await instance.createPerson(“Test person A”, 20, 190, {from: accounts[0], value: web3.utils.toWei(“1”, “ether”)});
//deletePerson(address creator) public onlyOwner
//Account[5] created the person, only account[5] can delete this person
await truffleAssert.fails(instance.deletePerson(accounts[0], {from: accounts[0]}), truffleAssert.ErrorType.REVERT);
});

result :
image

After changing account to [1] …

it(“Only owner can delete … test”, async function(){
let instance = await People.deployed();
await instance.createPerson(“Test person A”, 20, 190, {from: accounts[1], value: web3.utils.toWei(“1”, “ether”)});
//deletePerson(address creator) public onlyOwner
//Account[5] created the person, only account[5] can delete this person
await truffleAssert.fails(instance.deletePerson(accounts[1], {from: accounts[1]}), truffleAssert.ErrorType.REVERT);
});

image

FOUND THE REASON … account[0] is the OWNER …

Here my result :

1 Like

Hello @filip,

I’m having some confusion about addresses.

If I understand correctly the contract People has its own address (eg. 0000).

Then there is the owner which has another address (eg. 1111) and the owner address (owner msg.sender) is saved in the Ownable contract to restrict some function only to Owner.

When a new user create it’s own account (newPerson) his address is different from all the previous ones (eg. 3333) and is saved both in the array creatorsand associated to his newPerson with the mapping people.

  1. Now in the unitesting we get the contract owner with accounts[0].
    How is possible if the owner address is not passed into the array creators in the contract people?

  2. when creating a person await instance.createPerson("Lisa", 35, 160, {from: accounts[2], value: web3.utils.toWei("1", "ether")}); if we don’t specify from: accounts[2] which address will be used? accounts[1] and each time will follow wiht next array index?

  3. why if I specify the account in the test “should set senior status correctly” it give me error? await instance.createPerson("Bob", 65, 190, {from: accounts[1], value: web3.utils.toWei("1", "ether")});

error ` 1) should set senior status correctly

Events emitted during test:
---------------------------

People.personCreated(
  name: 'Bob' (type: string),
  senior: true (type: bool)
)


---------------------------
2) should set age correctly
> No events were emitted`

Sorry for the long post but I’m quite confused

const people = artifacts.require(“people”);
const truffleAssert=require(“truffle-assertions”)

contract(“people”,async function(accounts){
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 enogh payment”,async function(){
let instance= await people.deployed();
await truffleAssert.fails(instance.createPerson(“bob”,50,190,{value:1000}), truffleAssert.ErrorType.REVERT);
})
it(“should set person property 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 && result.age.toNumber()==65,“person not set correctly”);
})
it(“shouldn’t delete person if caller is not owner”,async function(){

  let instance= await people.deployed();
  await instance.createPerson("bob",65,190,{value:web3.utils.toWei("1","ether")});
  let result=await instance.getCreator(0);
  await truffleAssert.fails(instance.deletePerson(result,{from:accounts[2]}), truffleAssert.ErrorType.REVERT);

})
});

lmao, I went on and did something different than the original solution :sweat_smile:

 it("checks the owner of the contract", async () => {
    let instance = await People.deployed();
    await instance.deletePerson(account[0]);
    let ownerAddress = await instance.owner();
    assert(ownerAddress === account[0], "user is not the owner");
  });

  it("only deletes when owner", async () => {
    let instance = await People.deployed();
    await truffleAssert.fails(
      instance.deletePerson(account[1]),
      truffleAssert.ErrorType.REVERT
    );
  });

Also, I’d like to understand how the contract took accounts[0] as it’s owner because we nowhere defined it explicity?

Ciao @enrico

  1. Now in the unitesting we get the contract owner with accounts[0].
    How is possible if the owner address is not passed into the array creators in the contract people?
  2. when creating a person await instance.createPerson("Lisa", 35, 160, {from: accounts[2], value: web3.utils.toWei("1", "ether")}); if we don’t specify from: accounts[2] which address will be used? accounts[1] and each time will follow wiht next array index?
  3. why if I specify the account in the test “should set senior status correctly” it give me error? await instance.createPerson("Bob", 65, 190, {from: accounts[1], value: web3.utils.toWei("1", "ether")});
  1. Although I have not seen your contract, I do think that you are setting the contract owner in your constructor, something like this:
address public owner;

constructor () public {
   owner = msg.sender;
}

By default, the deployer account is always accounts[0] so this is why your owner is set to accounts[0].

  1. If you do not specify any accounts in your testing, then the default account will be used automatically (accounts[0]).

  2. I should check your smart contract for that :slight_smile: Can you please upload it to GitHub and send me the link to the repo?

Happy learning,
Dani

1 Like

Hey @vnaysngh

I copy/paste part of my answer to Enrico,

Also, I’d like to understand how the contract took accounts[0] as it’s owner because we nowhere defined it explicity?

  1. Although I have not seen your contract, I do think that you are setting the contract owner in your constructor, something like this:
address public owner;

constructor () public {
   owner = msg.sender;
}

By default, the deployer account is always accounts[0] so this is why your owner is set to accounts[0].

Regarding your tests, the only things that you should change are:

let instance = await People.deployed();
let instance = await People.deployed();

These should be declared in a before or beforeEach function.

Happy coding,
Dani

1 Like

contract (“People”, async function(accounts){
it(“should create a person”, async function(){
let instance = await People.deployed();
assert (instance.createPerson(“henni”, 61,190, {value: web3.utils.toWei(“1”, “ether”)}));
});

it (“should have the same creator address as the owner addres”, async function(){
let instance = await People.deployed();
let creator_address = msg.sender();
let owner_address = await instance.owner();
assert(creator_address === owner_address, “user is not the owner”);
assert.equal(creator_address, owner_address, “creator and owner should be the same”);
});
it (“shouldn’t be possible to delete a person if itsnt the owner”, async function(){
let instance = await People.deployed();
await truffleAssert.fails(instance.deletePerson(accounts[0]) ({from: accounts[3]}), truffleAssert.ErrorType.REVERT);
});

But something is wrong with my accounts(accounts not defined):

  1. should have the same creator address as the owner addres:
    ReferenceError: msg is not defined
    at Context. (test/PeopleTest.js:34:27)
    at process._tickCallback (internal/process/next_tick.js:68:7)

  2. shouldn’t be possible to delete a person if itsnt the owner:
    ReferenceError: accounts is not defined
    at Context. (test/PeopleTest.js:41:53)
    at process._tickCallback (internal/process/next_tick.js:68:7)

There was already a test above in the code that created a person, so I just tried to delete that for my new tests.

it(“should prevent non-owners from deleting the person”, async function(){
let instance = await People.deployed();
await instance.deletePerson(‘0x7a601df2c5F0Fddc4073A2E36D8228Be8E3F44bf’);
});
it(“should let owner delete the person”, async function(){
let instance = await People.deployed();
await instance.deletePerson(‘0x976A4ca20eE911FeD7995d2e30FdD71D9BA8df95’);
});

1 Like