DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

The software you build is only as secure as the code that powers it. Learn how malicious code creeps into your software supply chain.

Apache Cassandra combines the benefits of major NoSQL databases to support data management needs not covered by traditional RDBMS vendors.

Generative AI has transformed nearly every industry. How can you leverage GenAI to improve your productivity and efficiency?

Modernize your data layer. Learn how to design cloud-native database architectures to meet the evolving demands of AI and GenAI workloads.

Related

  • The Cypress Edge: Next-Level Testing Strategies for React Developers
  • Efficiently Migrating From Jest to Vitest in a Next.js Project
  • Advanced Error Handling in JavaScript
  • Building a Tic-Tac-Toe Game Using React

Trending

  • Immutable Secrets Management: A Zero-Trust Approach to Sensitive Data in Containers
  • How To Develop a Truly Performant Mobile Application in 2025: A Case for Android
  • Cosmos DB Disaster Recovery: Multi-Region Write Pitfalls and How to Evade Them
  • Endpoint Security Controls: Designing a Secure Endpoint Architecture, Part 2
  1. DZone
  2. Coding
  3. JavaScript
  4. Exploring TDD in JavaScript with a small kata

Exploring TDD in JavaScript with a small kata

By 
Giorgio Sironi user avatar
Giorgio Sironi
·
Apr. 21, 11 · Interview
Likes (0)
Comment
Save
Tweet
Share
12.9K Views

Join the DZone community and get the full member experience.

Join For Free

A code kata is an exercise where you focus on your technique instead of on the final product of your mind and fingers. But a kata can also be used as a constant parameter, while other variables change, like in scientific experiments. For example, when learning a new programming language or framework, you can execute an old kata in order to explore it.

I decided to perform a small and famous Kata that we used also during interviews to separate programmers from not programmers: the FizzBuzz kata. My goal was to learn how to setup a platform for Test-Driven Development in JavaScript, following the advice of the Test-Driven JavaScript Development book.

The parameters that change from my habits are the tools for running tests and the programming language, but my IDE (Unix&Vim) remained fixed along with the Kata:

  • Write a function that returns its numerical argument.
  • But for multiples of three return Fizz instead of the number and for the multiples of five return Buzz.
  • For numbers which are multiples of both three and five return FizzBuzz.
  • Additional requirement: when passed a multiple of 7, return Bang; when passed a multiple of 5 and 7, return BuzzBang; and so on for all the combinations.

As my tools for running the tests, I used JsTestDriver and Firefox, as suggested by the book Test-Driven JavaScript Development which I'm currently reading.

JsTestDriver

JsTestDriver will make you feel the joy of a green bar again. Download its jar, put it somewhere and add an alias in your .bashrc:

export JSTESTDRIVER_HOME=~/bin
alias jstestdriver="java -jar $JSTESTDRIVER_HOME/JsTestDriver-1.3.2.jar"

Start the server:

jstestdriver --port 4224

Point an open browser (I used Firefox) to localhost:4224. The browser will ping it via Ajax requests undefinitely to gather tests to run. Now we can use the command line to run tests, like you'll do with PHPUnit if you are a PHPer:

jstestdriver --tests all

The Kata

I started with a simple function, fizzbuzz(), and a single test case. I never wrote a test with JsTestDriver before so I needed to gain some confidence and be sure the configuration file was correct.

server: http://localhost:4224

load:
- src/*.js
- test/*.js

In JsTestDriver, a Test case is created by passing to TestCase (global function provided by JsTestDriver) a map containing anonymous functions.

TestCase("FizzBuzzTest", {
    "test should return Fizz when passed 3" : function () {
        assertEquals("Fizz", fizzbuzz(3));
    }
});

The functions whose names start with test will be executed; there are some reserved keywords like setUp which are used as hooks for fixture creation.

Running the test with the alias command is really simple:

jstestdriver --tests all

I made the first test pass with fizzbuzz.js, a file containing a first version of the function (with a fake implementation):

function fizzbuzz()
{
    return 'Fizz';
}

The result? A green bar (metaphorically green; all tests pass.)

.
Total 1 tests (Passed: 1; Fails: 0; Errors: 0) (0,00 ms)
  Firefox 4.0 Linux: Run 1 tests (Passed: 1; Fails: 0; Errors 0) (0,00 ms)

You can capture more than one browser if you want to run test simultaneously in all of them, but it will probably slow down the TDD basic cycle. You can leave cross-browser testing for later.

Going on

After this first test, I went on adding new ones and making them pass, until I even converted the function to an object, for the sake of easy configuration (a function returning a function would be the same).

Since I also needed to create the object in just one place, I started using setUp for the fixture creation:

TestCase("FizzBuzzTest", {
    setUp : function () {
        this.fizzbuzz = new FizzBuzz({
            3 : 'Fizz',
            5 : 'Buzz',
            7 : 'Bang'
        });
    },
    "test should return the number when passed 1 or 2" : function () {
        assertEquals(1, this.fizzbuzz.accept(1));
        assertEquals(2, this.fizzbuzz.accept(2));
    },
    "test should return Fizz when passed 3 or a multiple" : function () {
        assertEquals("Fizz", this.fizzbuzz.accept(3));
        assertEquals("Fizz", this.fizzbuzz.accept(6));
    },
    "test should return Buzz when passed 5 or a multiple" : function () {
        assertEquals("Buzz", this.fizzbuzz.accept(5));
        assertEquals("Buzz", this.fizzbuzz.accept(10));
    },
    "test should return FizzBuzz when passed a multiple of both 3 and 5" : function () {
        assertEquals("FizzBuzz", this.fizzbuzz.accept(15));
        assertEquals("FizzBuzz", this.fizzbuzz.accept(30));
    },
    "test should return Bang when passed a multiple of 7" : function () {
        assertEquals("Bang", this.fizzbuzz.accept(7));
        assertEquals("Bang", this.fizzbuzz.accept(14));
    },
    "test should return FizzBuzzBang when it is the case" : function () {
        assertEquals("FizzBuzzBang", this.fizzbuzz.accept(3*5*7));
    }
});

You can use this to share fixtures between the setUp and the different test methods: the test does not look different from JUnit and PHPUnit ones.

Like in all xUnit testing frameworks, the setUp is executed on a brand new object for each test, to preserve isolation. I like a bit the way in which in JavaScript you can tear and put together objects: after all, it's called object-oriented programming, not class-oriented programming.

I decided to use a small function constructor as you may infer from the test:

function FizzBuzz(correspondences) {
    this.correspondences = correspondences;
    this.accept = function (number) {
        var result = '';
        for (var divisor in this.correspondences) {
            if (number % divisor == 0) {
                result = result + this.correspondences[divisor];
            }
        }
        if (result) {
            return result;
        } else {
            return number;
        }
    }
}

All the code is on Github, to see the intermediate steps of the Kata if you need them. You can also use the repository to try out your installation of JsTestDriver: a git pull followed by running the tests will confirm that it's working.

Sometimes we don't test code in alien environments like JavaScript console or database queries because we don't know how; but a Kata which takes just two Pomodoros can solve the issue and let you enjoy a green bar even when working with a browser's interpreter.

Kata (programming) JavaScript Testing

Opinions expressed by DZone contributors are their own.

Related

  • The Cypress Edge: Next-Level Testing Strategies for React Developers
  • Efficiently Migrating From Jest to Vitest in a Next.js Project
  • Advanced Error Handling in JavaScript
  • Building a Tic-Tac-Toe Game Using React

Partner Resources

×

Comments

The likes didn't load as expected. Please refresh the page and try again.

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • support@dzone.com

Let's be friends: