Unit Testing in Truffle

Hi @matren,
I believe you have a little copy&paste hick-up in your last test :slight_smile:

it("should be that contract balance equals internal balance after people creation", async () =>
    {
        let instance = await People.deployed();
        await instance.createPerson("Stranger", 30, 176, {value: tcost, from: stranger});
        let contract_balance = Number(await web3.eth.getBalance(instance.address));
        let internal_balance = Number(await web3.eth.getBalance(instance.address));
        assert(contract_balance == internal_balance, "internal balance does not match contract balance")
    });

You fetch contract_balance and internal_balance from the same place (on chain). Hence, your test would not find any issues with the contract’s internal balance.

1 Like

JRB, I inserted into my migrations file the command

 console.log("Contract address: " + instance.address + "\n");

and found that the address displayed is the same as the contract address in ganache (click on “Deployed” next to your “People” contract and ganache will show you the contract address in the first line).

1 Like

yes XD, I missed await, its really important I see. Have you notices another thing?
suppose you can write the following code and it works fine,

it("should bla bla bla...", function(){
   let instance = People.new();
   instance.createPerson(...,...,...);
});

so if we don’t mention the function to be async, the function calls don’t require await, so why do we use async at first place? Can we go without it?

Shame on me !
Must be something wrong with my keyboard :flushed:

Honorable you had the patience to check my code
(i can image more exciting stuff than doing code reviews) !

I should try a TDD approach next time.
Thanks for your feedback. :+1:

1 Like

This example should not work because People.new() returns a promise. Without async/await instance.createPerson() will throw an error since the promise does not have the method createPerson().

It needs to be modified in the following way:

it("should bla bla bla...", async function(){
   let instance = await People.new();
   await instance.createPerson(...,...,...);
   console.log('Person created');
});

Basically async/await is just a different notation for handling asynchronous code. Your example could also be written in the following way:

it("should do something", function(){
  People.new().then(instance => {
    instance.createPerson('Bob', 40, 100).then(() => {
       console.log('Person created');
    })
 });
});

imho, the first way is a lot more readable. Here’s a good comparison between the two ways of using promises (well, biased towards async/await though :slight_smile: )

If you are struggling with asynchronous code you might wanna check out the JS course here in the academy. If it’s as good as the other courses I’ve done so far it should be very helpful.
Just quickly checked the course and asynchronous code does not seem to be a topic.

2 Likes

Hey @FrankB!
I tryed what the comand that you put in the reply, however, the test threw an ererr:


You mentioned that I can allso find the contract address in the “contracts” tab in Ganache. I tryed that. However when I looked, the people contract was not deployed. I think that I did something wrong in preveos videos that might have afected something.

Here is what the “contracts” tab in Ganache looks like for me.


Thanks for your help anyway!

Yes, you need to focus first on deploying the contracts. So the contract and the migration file must be properly set up. Once you got that done and your People contract is properly deployed, you can go back to the testing problem. So run the ‘migrate --reset’ command and see what kinds of error messages you are getting.

Here is my value-testing program (all tests passed):

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

 contract("People", async function(accounts){
   let instance;
   beforeEach(async function(){
     instance = await People.deployed()
   });
   it("should emit delete-person event with owner address", async function(){
     await instance.createPerson("Babette", 16, 160, {from: accounts[4], value: 
     web3.utils.toWei("1", "ether")});
     let tx = await instance.deletePerson(accounts[4]);
     truffleAssert.eventEmitted(tx, 'personDeleted', {deletedBy: accounts[0]});
   });
   it("should adjust the balance properly in the contract", async function(){
     let oldBalance = await instance.getBalanceContract();
     await instance.createPerson("Babette", 16, 160, {from: accounts[5], value: 
     web3.utils.toWei("1", "ether")});
     let newBalance = await instance.getBalanceContract();
     assert(1*oldBalance + 1*web3.utils.toWei("1", "ether") === 1*newBalance, "balance not 
     properly adjusted in the contract");
   })
   it("should adjust the balance properly on the blockchain", async function(){
     let oldBalance = await web3.eth.getBalance(instance.address);
     await instance.createPerson("Babette", 16, 160, {from: accounts[6], value: 
     web3.utils.toWei("1", "ether")});
     let newBalance = await web3.eth.getBalance(instance.address);
     assert(1*oldBalance + 1*web3.utils.toWei("1", "ether") === 1*newBalance, "balance not 
     properly adjusted on the blockchain");
   })
   it("should reduce the balance in the contract to zero if all funds are withdrawn", async 
   function(){
     await instance.withdrawAll();
     let newBalance = await instance.getBalanceContract();
     assert(1*newBalance === 0, "balance in the contract not reduced to zero");
   })
   it("should reduce the contract balance on the blockchain to zero if all funds are 
   withdrawn", async function(){
     await instance.createPerson("Babette", 16, 160, {from: accounts[7], value: 
     web3.utils.toWei("1", "ether")});
     await instance.withdrawAll();
     let newBalance = await web3.eth.getBalance(instance.address);
     assert(1*newBalance === 0, "contract balance on the blockchain not reduced to zero");
   })
   it("should not allow a non-owner to withdraw all funds", async function(){
     await instance.createPerson("Babette", 16, 160, {from: accounts[8], value: 
     web3.utils.toWei("1", "ether")});
     truffleAssert.fails(instance.withdrawAll({from: accounts[1]}));
   })
   it("should allow the owner to withdraw all funds", async function(){
     await instance.createPerson("Babette", 16, 160, {from: accounts[3], value: 
     web3.utils.toWei("1", "ether")});
     truffleAssert.passes(instance.withdrawAll({from: accounts[0]}));
   })
   it("should deposit all the withdrawn funds in the owner's account", async function(){
     let oldAccountBalance = await web3.eth.getBalance(accounts[0]);
     await instance.createPerson("Babette", 16, 160, {from: accounts[9], value: 
     web3.utils.toWei("1", "ether")});
     let contractBalance = await instance.getBalanceContract();
     let tx = await instance.withdrawAll();
     let gasUsed = BigNumber(tx.receipt.gasUsed);
     let gasPrice = BigNumber(20000000000);
     let gasCost = gasPrice.times(gasUsed);
     let newAccountBalance = await web3.eth.getBalance(accounts[0]);
     assert(1*oldAccountBalance + 1*contractBalance - gasCost === 
     1*newAccountBalance, "balance not properly deposited in the owner's account");
   })
 });

Hey @FrankB!
I removed my workspace in Ganache of my “Peopleproject”. I then created it again and then redeployed the contracts. I don’t know how but it worked! I now now the contract address.

Hi guys,

Need help on testing. I am having trouble with the truffleAssert function. I followed Filip’s instructions to a tea, and installed truffle-assertions correctly, but instead of getting a pass, i get fail (see code and attachment below).

When i hover my mouse over “tru” in code line “const truffleAssert = require(“truffle-assertions”);”, it gives me this message. "Could not find a declaration file for module ‘truffle-assertions’. Try npm install @types/truffle-assertions if it exists or add a new declaration(.d.ts) file containing `declare module ‘truffle-assertions’;

Can you please help me figure this out?

Test code
const Peoplecontract = 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")}));

})

});

omg, stupid me. This is a careless error on my end. I realized I put const “Peoplecontract” instead of “People”.

Please ignore.

1 Like

Very good, JRB, I’m glad it worked out. Starting all over is always a good idea. I had some problems myself today that I was able to solve by reloading everything.

1 Like

My question is on the argument “accounts”

When you use argument “accounts” for any contract function, does Ethereum / Solidity automatically set to an array where account[0] = deployment / owner’s address? and remaining accounts for all other addresses?

I used “creators” array as that was the array used to store creators’ addresses and is defined in the People’s contract. But this doesn’t work, can you help me understand why we have to use “accounts” rather than “creators” array (which is already defined in the contract)

it(“shouldn’t delete if the address is not the owner”, async function(){

    let instance = await People.deployed();

    await instance.createPerson("Alice", 50, 100, {from: creators[0], value: web3.utils.toWei("1","ether")})

    await truffleAssert.fails(instance.deletePerson(creators[0], {from: creators[0]}), truffleAssert.ErrorType.REVERT);

});

Li_Sun, It seems to me that the creators array is internal to the contract and is as such a solidity array. The accounts array, by contrast, is a Javascript array that links the contract to ganache. You can verify this by writing all the account numbers of the accounts array onto the console. That;s what I did before I started with the assignment, in order to get a better idea of what is going on. It turned out that accounts[0] is indeed the owner;s address and that all the other addresses are identical to those listed in ganache. Hope that helps.

1 Like

To verify the owner and the delete function works correctly I had to add and define a variable for the accounts.


it("You aren´t the owner, you can´t delete people", async function(){
	let instance = await People.deployed();
	let accounts = await web3.eth.getAccounts();
	await instance.createPerson("Abby", 12, 165,{from: accounts[1], value: web3.utils.toWei("1","ether")});
	await truffleAssert.fails(instance.deletePerson(accounts[1], {from: accounts[1]}),
  truffleAssert.ErrorType.REVERT);
});
it("You are the owner, you can delete people", async function(){
	let instance = await People.deployed();
	**let accounts = await web3.eth.getAccounts();**
	await truffleAssert.passes(instance.deletePerson(accounts[1], {from: accounts[0]}));
})

I could add this line let accounts = await web3.eth.getAccounts(); when declaring before (async function () {}); ??

Eddited by @gabba : please use the preformatted text tag to share code thank you

@Thaddeus19 Thanks for reaching out!
Yes, you can declare it before the async function because your web3.eth.getAccounts() is coming from web3 module and not from the smart contract.

2 Likes

Thaddeus19, I don’t think you need to declare the accounts variable in this way. If you insert it in the initial declaration of the contract (i.e, in the line

contract(“People”, async function(accounts){…

then it all works fine. The accounts array, it seems to me, is defined externally. What I would like to know though is where exactly that definition is located.and how the link to ganache is established…

2 Likes

Great job @Stefan_Guse
Checking the gas price to make sure the correct amount has been sent is the perfect way to make sure everything went fine :+1:

I am not used to use the block number with getBalance it’s good to know . But why not just checking the balance before calling withdrawAll function ?

2 Likes

@matren Shame on me too ^^ i checked your first tests they were fine and it seems that i trusted truffle test for the second part instead of checking everything myself :blush:.
Thank a lot @Stefan_Guse for helping the community

1 Like

In this case you can emit events in your contract and check the event return value in your test.

Can you link your code , when it was not working ?

You need to delete the mapping to save space, by removing the value do you mean setting it to zero ?

2 Likes