Let’s Create a Discord Music Bot using Test Driven Development (TDD) Part 1

Aussy
5 min readAug 4, 2019

--

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.

Test Driven Development Cycle

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.

.babelrc

Next, we’ll want to setup our package.json and add a test script to easily run jest.

package.json

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.

Post-setup project structure (Visual Studio Code)

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:

tests/Bot.test.js

This might seem like a lot, so let’s break it down.

For our project, there are currently 3 things to keep in mind:

  1. We’ll have a Bot MusicBot that will handle commands
  2. We’ll have commands sent through messages Message that our Bot will have to handle/process
  3. Messages coming in will come from a chat room ChatRoom. This chat room has pretty straight forward functions, sending messages sendMessage 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

Current project structure after creating src files

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.

npm test results

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.

MusicBot.js

Run npm test and we should see a nice, green “PASS” result.

A passing test!

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!

sendMessage is still be called once.

Let’s modify our MusicBot.js code to fix this.

Now let’s see our test results

We passed!

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! ❤

--

--

Aussy

Software Developer with too much time on his hands