Developing your decentralised applications on Arweave ao is simple, all you have to do is, create variables and functions to store and modify your data, then create handlers which will handle the incoming messages and call the defined functions accordingly :)
But writing backend logic, that too for a radically new environment using a language that you might never have programmed in before, can be a daunting task. Moreover, you would not want there to be any loopholes in your code right?
Well, fear not because in this guide we will be looking at how you can write unit tests for your functions using the unit testing module by Tom.
At the end of this article you will be able to create and run unit tests and get the results just the this screenshot:
We will be using BetterIDEa, which is an online IDE specialised for AO, as our development environment. Here you can easily install packages and write code in its notebook like ui
To get started, visit ide.betteridea.dev and connect your web wallet
Once connected, create a new project and give it a name you want. I’ll name it ‘how-to-unit-test‘. Next we need to tell the IDE which process it should run the code in, you can choose a previously created process or spawn a new one. I will create a new one and name it ‘unit-tester‘
And that’s it, hit create project and within seconds you’ll have your notebook up and running. Try running the default code and you should get an output saying “Hello AO!“
We’ll start simple, by creating a chatroom 🤭
Feel free to follow along and create multiple cells to write and run the different functions we will be making
Initialise a chatroom table
Function to register a nickname
Function to send a message
Function to get all messages
Chatroom = {
messages = {},
users = {}
}
return Chatroom
Write the above code in a code cell and run it. You should get an output that prints an empty table with empty messages and users fields.
function setNickname(userAddress, nickname)
Chatroom.users[userAddress] = nickname
end
This code snippet adds an entry to the Chatroom.users
field to store their nickname
function sendMessage(from, message, timestamp)
local nickname = Chatroom.users[from] or ""
local msg = {
from = from,
nickname = nickname,
timestamp = timestamp,
message = message
}
table.insert(Chatroom.messages, msg)
end
This code snippet checks if the user has a nickname, and appends message data to the Chatroom.messages
table
function getMessages()
return Chatroom.messages
end
This function just returns all of the messages that have been sent in the chatroom
To check if these functions that we have defined work, let’s try running each of them one by one and see if they work.
Starting with setNickname
, if we pass our process id and a string, it should add an entry to Chatroom.users
Next we try running the sendMessage
function and pass our process id, the message and a timestamp (0 for testing), and can see that an item has been added to Chatroom.messages
lastly, getMessages also works as expected
Fear not, we are going to add exactly that now :)
For adding checks, we will use the assert function that lua provides, to make sure our conditions are met, else an error gets thrown
assert(condition, "error message if condition is false")
and we can put anything in condition, for example:
whole variables to check if they have been defined
size of tables or strings
comparisons between variables
Some checkers we can add to our chatroom app are:
Check if message is a string
Check if size of ao.id is 43 (standard process id size)
If timestamp is a number and nothing else
If nickname has at least 3 characters
assert(type(userAddress) == "string", "user address should be a string")
assert(#userAddress == 43, "invalid user address size")
assert(#nickname >= 3, "nickname should be atleast 3 characters long")
assert(type(message) == "string", "message should be a string")
assert(#from == 43, "invalid process id size")
assert(type(timestamp) == "number", "timestamp should be a number")
Add the given snippets to the start of setNickname
and sendMessage
functions.
Now if we call these functions with some unwanted data, it should throw errors like this
Head over to the top right on the IDE and click on the Modules icon. A dialog box should open, asking you which module to load, simply select Test and hit load.
(feel free to inspect the code that will be loaded on your process)
Now we can import the module using the require function.
Lets try running the example code from the repos example.lua file
local Test = require("Test")
local myTests = Test.new('example tests')
myTests:add("ok", function () assert(true, 'passing test') end)
return myTests:run()
And as you can see it runs the tests and prints the results for passed and failed cases
Lets create a tests for our chatroom
local Test = require("Test")
chatTests = Test.new('Chatroom unit tests')
return chatTests
Run this in a module and have a look at the result
Let’s create and add tests for our functions.
To create a test, wrap your intended function around another function() … end
block and pass it to the chatTests:add()
function along with a name for this test
Like this 👇
chatTests:add("verify table", function()
assert(type(Chatroom)=="table", "Chatroom is not a table")
end)
chatTests:add("verify users table", function()
assert(type(Chatroom.users)=="table", "Chatroom.users is not a table")
end)
chatTests:add("verify messages table", function()
assert(type(Chatroom.messages)=="table", "Chatroom.messages is not a table")
end)
To check the sendMessage function
Chatroom.messages = {}
chatTests:add("send message", function()
sendMessage(ao.id, "hi", 0)
end)
chatTests:add("verify message sent:1", function()
assert(#Chatroom.messages == 1, "Message was not logged")
end)
chatTests:add("verify message sent:1", function()
assert(Chatroom.messages[1].message == "hi", "Message content is different")
end)
These tests send a message, then check in the Chatroom.messages
table wether the message data was added accurately.
Lastly add tests for checking the setNickname
function, 2 of which are set to fail deliberately
chatTests:add("set nick", function()
setNickname('O1d7qSBUEyDMBd8JuljtGo2vPhX-LFn5DUEObX2GCMc','ankush')
end)
chatTests:add("set nick", function()
setNickname('7quc6o_k8O2DA0YD0sqZ0brsTVFhZVaRznNZ6KxahmY','weeblet')
end)
chatTests:add("set nick:fail", function()
setNickname('illegal-id','weeblet')
end)
chatTests:add("set nick:fail", function()
setNickname(ao.id,'aa')
end)
Feel free to add our own tests too 💡
Then finally we run the tests and look at the results
Wasn’t that simple 🤩
You can access the full notebook here 👇
For any questions or if you need help, feel free to join the BetterIDEa discord community
Thank you for reading ;)