Let’s Create a Discord Music Bot using Test Driven Development (TDD) Part 1
If you’re reading this, you probably already know the TDD routine. Write tests that fail, write code that passes the test, refactor (if needed), repeat.
If you’re like me, once you try to apply it to your next project, you get stumped. A lot of tutorials tend to explain the concept, with a short example involving a multiply and divide function with unit tests. But our projects tend to get a bit more complicated than that, don’t they?
Fortunately, I’ve managed to stumble my way through, and have decided to write this guide to help others apply TDD to more real world applications.
Today we’ll be creating a bot for Discord, applying TDD concepts using Jest (our testing framework), Discord.js (library for creating Discord Bots), youtube-dl (for grabbing YouTube videos, more on this later), and a touch of Babel to get those nice ES6 features.
By the end of this tutorial series, we will have a bot that can take a command such as
!play https://www.youtube.com/watch?v=w2Ov5jzm3j8
And join the user’s voice channel to stream the audio of the youtube video to the voice chat. Sounds complicated enough to get dirty with TDD, while still being simple enough to get things working quick!
Setting Up
First we’re gonna create a new Node.js project and install our dependencies. Create a new folder and run the following commands
# Initialize new node project
npm init# Install testing and babel dependencies.
# --save-dev for these as they're used only for development
npm install --save-dev jest @types/jest @babel/core @babel/plugin-transform-runtime @babel/preset-env @babel/runtime#Install application dependencies
npm install --save youtube-dl discord.js
Now we’ll setup a .babelrc file in the root of our project to get those ES6 features we mentioned.
Next, we’ll want to setup our package.json and add a test script to easily run jest.
Finally, we’ll create 2 folders. A test folder, and a src folder. One to hold our tests, and one to hold our actual code.
That’s it! By the end of the setup, your project structure should look something like this.
Our first Test, ping pong
We’ll start small to get our feet wet. Let’s give our bot a !ping command. When the bot sees a !ping message, we’ll simply send pong.
Following TDD, we have to make a failing test first to get started. Here’s the first test I wrote:
This might seem like a lot, so let’s break it down.
For our project, there are currently 3 things to keep in mind:
- We’ll have a Bot
MusicBot
that will handle commands - We’ll have commands sent through messages
Message
that our Bot will have to handle/process - Messages coming in will come from a chat room
ChatRoom
. This chat room has pretty straight forward functions, sending messagessendMessage
and voice chat (more on this soon)
For our project, we also want our tests to be fast, so we mock our own ChatRoom
so we can monitor how the bot interacts with it.
Acing the Test
Let’s run our test real quick:
npm test
You should be greeted with a giant FAIL result due to not finding our modules. Perfect! Let’s pass this test.
Let’s tackle these import issues first. Let’s create the missing src files that we’re trying to import, ChatRoom.js, Message.js, and MusicBot.js
Let’s give these new files some default exports. We’ll simply create an empty class for each, with a constructor for our Message
class:
Let’s run our test command again.
Sounds pretty straight forward, our MusicBot
is just an empty class. Let’s fill it up ace this sucker! All we need to do is send a ‘pong’ response through the ChatRoom.
Run npm test
and we should see a nice, green “PASS” result.
More Tests!
Hopefully you’re a bit concerned about our implementation. Our “message handler” is simply sending a pong every time. You may be tempted to go in and change the MusicBot.js file to have an if statement, but you’d be breaking the rules of TDD. You should be writing code to pass a test.
So what do we do? Write another test! Let’s write up a case where our bot should NOT send a response. Let’s add the following code under the first test we wrote.
Run our tests, and uh oh!
Let’s modify our MusicBot.js code to fix this.
Now let’s see our test results
Nice!
Conclusion
“Whoah, shouldn’t there be more?” you may be thinking. Turns out writing tutorials can be pretty time consuming, and get lengthy fast! I will be making a Part 2 soon where we will hook this up to an actual discord bot and see it in action!
Let’s go over what we’ve done so far. We’ve managed to write an abstract Bot that can take messages and reply accordingly. Big emphasis on abstract, as you may notice that we don’t have an actual Discord bot live yet.
This is a good thing! We should focus on the core logic of our bot for now. Not only will it keep things simple, but it will also makes it a lot easier to maintain and update without messing with outside APIs like Discord.
This is the first tutorial I’ve wrote in a long time, please let me know what you think. Was it too lengthy? Should some sections be cut or extended on? Did this actually help!? Would love to know what you think! ❤