I want to (a) set up a simple server that can save and retrieve data from a database, (b) test the entire system using a testing framework, (c) compare test driven development (TDD) systems to behavior driven development (BDD) systems.
A form submission is the most common way to implement data saving and retrieval. I use NodeJS to handle this. MySql is a very popular database system and interfaces well with NodeJS, so I use that. Finally, my testing environment is Mocha.
Plan of action
- Step 1: Set up the node environment on your system. There are many guides (like here, here and here) that go into sufficient detail on how to set up NodeJS on your system, so I shall not describe the process in detail.
- Step 2: Set up a base project. Create a separate directory for it. Create a package.json file and fill it with the following. Note, I shall amend the package.json dependencies in the future.
As you can see, I make some assumptions here regarding the specifics of the project structure, like what database connection libraries I am going to use. This will become relevant in the “TDD vs BDD” section of this post. However, mostly, I will set up which testing libraries needed.
Run npm install in the project folder command line to see these libraries appear in a directory called node_modules.
- Step 3: Create a list of technical specifications and the tests that exercise them. The tests should all go within a folder named test that will sit within the root project folder. Create a file called test-BDD.js underneath it.
Next, I will set up our requirements and plan tests that validate the requirements.
The requirements are as follows:
- Requirement 1: Landing page functionality
- 1.1 Need to see text on the landing page.
- 1.2 Need to see the link to the login page.
- Requirement 2: Login page functionality
- 2.1 Need to see text on the login page.
- 2.2 Need to be able to login with user/email “TEST”/”TEST”.
- 2.3 Need to not be able to login with user/email not “TEST”/”TEST”.
- 2.3.1 If logging in with user/email not “TEST”/”TEST”, redirect to the login page.
- Requirement 3: Form page functionality
- 3.1 Need to see text on the form page.
- 3.1.1 Need to be able to see the text for the input box.
- 3.1.2 Need to be able to see all the previous inputs listed.
- 3.2 Need to be able enter lname/fname values.
- 3.2.1 Need to be able to see entry in the database.
- 3.2.2 Need to be able to see entry on the page.
- 3.3 Need to see the link to the login page.
Write the tests to match these specs in test-BDD.js.
Ensure your mysql instance is running, then run these tests by entering mocha on the command line. You will see a set of errors. This simply means that the code that the tests are running against has not been written up yet.
- Step 4: Write the server code in order to pass the tests.
From the tests, it is clear that I need a way to visit 3 pages: home, login, and form. Each of them needs to show certain texts. Additionally, on form submissions in the login and form pages, there should be data retrieval changes.
To run any of this, I need a server. In this case, I will use server.js. In order to run the web application I’ll use the popular express framework: http://expressjs.com/. Note: In order to see these express libraries appear in our node modules, I need to add them to my package.json dependencies:
Within the server.js, I will initialize the app and require that it use the bodyParser helpers to be able to easily access the body text later on. I will reference files for routing and styles, that I export to the routing.js file and styles folder for modularity. Finally, I will send a console message for our notification, then export the resulting server.
Within the referenced styles folder, I write the stylesheet main.css:
I code the router, router.js, setting the serverport to listen to the server.js at port 3000. Additionally, I will use the view engine hbs (http://handlebarsjs.com/) which also needs to be added to the dependencies in package.json as “hbs”: “2.4.0″.
Within the router, I route requests for the home page, login page, and form page:
In the forms controller form.js, (which I will put in a new folder ‘./controller/’ for readability), I put:
After I establish the connection to the database, I set up the functions to be called for each route.
GET /home should simply show the home page.
GET /login should simply show the login page form.
PUT /login should process the login page form according to some rules (for e.g. proceed only if the user has an account).
PUT /form should process the form page form and add the new first and last names to the database.
Returning to the home folder and running mocha now (again simply type mocha and press enter) would toss me the error:
Cannot find module ‘../database’
To resolve this, I need to now create the module that will interact with our database. In our root folder, I create the file database.js.
In it, I add:
As without the mysql module I cannot start any connection. I then set the attributes of the table we intend to connect to:
The details for this connection are dependent on your local mysql setup. I will use localhost as our host as I intend to access the database locally and port 3306 as it is the default. For the user, password and database entries you need to enter your local details. This creates A connection to the database that export for use elsewhere in our application.
Running mocha now runs this test and I’m able to see the results; and they are all the failing results. To pass the tests, I look to see what is missing. I see: ‘Failed to lookup view “../views/..”’
To fix this I create the templated viewed pages. For readability I create a new folder, ./views/ for them.
I start with the home page, home.hbs which is quite elementary:
Running mocha now passes one test. The next two pages have the forms and are bit more complicated. First we create the login page, login.hbs.
Running mocha now passes up to 4 tests. It still throws an Uncaught AssertionError for “Login page functionality Able to login with user/email “TEST”/”TEST”” due to no form.hbs.
We now create that too:
Running mocha again passes us all 7 tests, proving that all components are in place. We’ll now see the specifics our testing approach and the higher level concepts behind them.
TDD vs BDD
In this post, we see that the systematic running of tests and coding to meet their specs has given us a code base that is both accurate and automatically test-verified. This kind of coding is generally called Test Driven Development (TDD). However, in the above example, we don’t start with developer-written tests. To the contrary, we use tests that match (nearly literally) what the client expectations are. Hence, the appropriate terminology for these tests would be Behavior Driven Development (BDD). Mocha provides us the ability to do contrast between BDD and TDD. For example, here are the same tests written in a TDD format, written into a new test file, test-TDD.js and run with mocha.
Here you need to run it specifically as mocha -u tdd. BDD may be run with the tdd flag, but not the other way around.
As you can see, outside of a few term changes (before->setup, describe->suite, it->test), the tests are identical, which shows us how similar the ideas are. The difference between them seem to be a purely theoretical one, being a manner of approach.
- TDD is intended for unit- and low-level testing and is intended to test that the individual functional units are working.
- BDD is intended for client level testing and to prove that behavioral flows are working.
- For example, testing that the login form controller can accept valid information, filter incorrect ones, and push it through to the database (while testing edge cases of the database acceptance) would a TDD approach. A BDD approach would be to test if the user can log in using a variety of the different users and observing the black box output, without focus on the internals.
There are a variety of debated theories on what is the correct approach and what should/should not be done. Here are my ideas on the subject. Choosing your approach is critically dependent on your project needs (size, stack, etc.) and your management/client (their involvement, knowledge, etc.), making the choice incredibly difficult. But, as a loose set of rules, I propose:
- Having a BDD approach will provide your client-team/managers a friendly interface to view how well-tested/strong your project is and will give them insight into what it is built to hold up against. A BDD approach can be seen as a top-down approach, using the high level specs to test the entire system. Further, having a BDD approach greatly accentuates the code visibility to those not directly involved.
- Having a TDD approach will provide a very clear map of the what functional units are working and broken, allowing for a quick method for finding issues, without breaking a whole array of integrated test suites. It can be seen as a bottom-up approach, using low level specs to make sure independent components are working.
- A hybrid between the two, like the two test files here, would provide a holistic solution.
- Whatever your approach is, coding against a set of tests is crucial as it will help prevent last-minute issue-fixes and provide better estimations of resource spending. The logic for the latter being that it provides a very clear metric of what works and what does not for all members of the project.
- Using test-based development demands that you have a good understanding of your stack before you begin coding.
The code source for the above project: https://github.com/skandamohan/Blog-Code-Node-JS-With-Mocha