In this lecture, we run through testing in Solidity and carry out a variety of tests on the game that we have been creating in previous courses in this learning path.
Now in this lecture, I want to talk a little bit about the testing before we actually start testing because there's some consideration that I want to have at least clarified before we are writing any tests. First of all, Truffle tests reside in the tests folder. Now that is a little surprising hopefully, but you can have two different kinds of tests. The one is JavaScript based tests and the other ones are Solidity based tests. So, they are really for exercising your contracts in advance, bare-to-the-metal spirit scenarios. We're going to write both, but we are very much focusing on the JavaScript tests because this is usually how your users will interact with your smart contracts from outside. You can start the Truffle tests with Truffle test and you can add the network's parameter as well at the end, or alternatively or in addition, you can also specify a specific test you want to run. Very important is that the tests run in a so-called clean-room environment. That means when you run your tests, then a Truffle will always try to re-deploy your smart contracts from scratch and you will begin with your smart contracts as if there was no interaction yet. So, you can always start from a fresh set of smart contracts which also means if you want to test specific situations, then you first have to get there.
Meaning if you want to test where people started to interact with your smart contract, like we in our game, we have this high score list and you want to test. What happens if we have already 10 people in our high score list and suddenly an 11th person is going to go into the high score list with a new high score? Then you have to start from scratch. You cannot just take your high score list that is already deployed. All right. The last thing on this page, what I want to talk about is the speed and reliability considerations, and you can run Truffle tests against any network you want to. That means anything that you have in your Truffle configuration defined as a network you can use to run your tests against. Now if you choose to run it against a real blockchain then you have for every command, every interaction with your smart contract, every writing interaction, you have to wait until the transaction is mined, and that can take a very long time. If you remember back how we deployed our smart contracts when we set our ganache to 10 seconds. Let me just re-deploy this here. We're going to-- Where is it? Here, then it's still running from the previous lecture where we said we're going to deploy it with 15 seconds. Block mining time, it was a little bit too fast. Let me close this 15 seconds. Block mining time, I didn't save it. Well, that explains something. So, then every time you run a test, every time you start to interact with your your blockchain, you need to wait. You need to wait until the transaction is mined. And if you have a lot of tests and if you run these tests with your teams and if you run these tests all the time you can make changes, it can become very very cumbersome.
So, you don't want to test very often or you want to test very, very little against a real blockchain with a high block mining time. If you test against a blockchain like a ganache without a block mining time where these transactions are mined instantaneously, then you'll save a lot of time and we're going to do just that, we are not using a real blockchain. All right, the last thing is if you write JavaScript tests, and we're going to do this in the next lecture, but there are two flavors how you can write JavaScript tests. Let me explain the first one which we are not going to use, and let me explain to you why in a second. So, usually you start to test with, you have a contract and then you'll describe this contract, you can have any name, it doesn't have to be the right contract name. Then you get this contract will call a callback function and give you the accounts that are available. So, you get the accounts that are available in the system and then you write actual test cases, you write, it ("should put 10,000 MetaCoin into the first account",() and then give it a function which does something, and then you say MetaCoin deployed(). So, you get the instance of the smart contract. Then you do something on the smart contract instance that getBalance.call, return that one, and then that one gives you again a promise which is then resolved, and then you get back to balance, and then you equal the balance. Now this is just a free liner actually but it gets very hard to read if you start to interact with other smart contracts, if you try to call a lot of functions. So, for example, it ("should send a coin correctly",(). So, you have two accounts and you have a starting balance and the ending balance, and then you'll get the get the instance of the smart contract and you return the balance and then you get the balance from the second account, and then you get the balance again, and then you send the coin, and then you do this and that. So, and you always need this then return, then return, then return, then return, and so on. So, there's an easier way and that is async/await, which is a newer version and I think is much more readable. And that one if you scroll down in the Truffle documentation and the writing tests in JavaScript, then you see immediately how this works.
So, you have to define a function as an async function, and as soon as you define this function as an async function, you can access this await keyword, and this await keyword will wait until the promise that is returned by MetaCoin.deployed will resolve and give you back the actual then part of the promise. So, you don't have to write MetaCoin.deployed but then instance is and so on. You can just write await MetaCoin.deployed and then give me back whatever it returns actually. It will stop executing the script at this point and actually wait for resolving the promise. Whereas, this one will continue executing the script and then execute the then part later on, there's a huge difference, and for us, for testing, it actually makes sense to wait for the promise to be resolved. And then you can just just work line by line, and for me that's much easier to read. Now obviously both things work and if you think the other one is better or easier to read, you roll with the other one. Not a problem at all, but for us, I think it's much easier to use that one, and I will use this one in this course in the next few lectures during this section. All right and that's all, and I would say we go ahead now and we're going to add our first JavaScript test for a game.
Tom is a CTO, senior back-end developer, and systems architect with over twenty years of hands-on development experience in a variety of languages and systems. He has a CS master's degree and has been working with Ethereum and blockchain technologies since 2016.