Praveen's Blog

An Eternal Quest for Incremental Improvement

Introduction to Test-Driven Development in C++ using Boost Test Library

TDD

I have been following Test-Driven Development for a few years now. Even though TDD is widespread, often I come across a few friends who aren’t very familiar with TDD approach. It took a while for me to really appreciate TDD since I was introduced to it. When I demonstrated TDD in action, I got a few of my friends interested.

We have our own test framework that we use in our project which was primarily developed by David Carlton. It works very well for our needs. However, for my personal projects, I wanted to try something that is more widely used in the industry. I started using CppUnit for a while until I found Boost Test Library coming a long way. Now, I use Boost Test Library for all my personal projects. It is very easy to setup tests and I really like it.

I also wanted to write a quick introduction to Boost Test Library. So, I thought that I will put down a screencast that will solve two purposes of demonstrating Boost Test Library and serve as an introduction to TDD. This is not an extensive demo or an introduction. I have chosen a really simple problem that is often asked in preliminary rounds of technical interviews. But, it is a good place to start. I don’t guarantee that the solution is efficient. But, it is correct to my knowledge. Please feel free to suggest issues or improvements. Please note that a HD version of this video is available when viewed on Vimeo’s site.

Problem

Implement a function int atoi(const std::string &val) that converts the given string in decimal notation to its integer value. Return 0 if the input is not a valid integer.

#include <string>

#define BOOST_TEST_MODULE atoi
#define BOOST_TEST_DYN_LINK

#include <boost/test/unit_test.hpp>

namespace impl {

int atoi(const std::string &val) {
    int result = 0;
    int multiplier = 1;
    bool negative = false;

    for (std::string::const_reverse_iterator i = val.rbegin();
         i < val.rend();  ++i) {
        if (*i <= '9' && *i>= '0' ) {
            result += (*i - '0') * multiplier;
            multiplier *= 10;
        } else {
            if (*i == '-' && i == val.rend() - 1) {
                negative = true;
            } else {
                return 0;
            }
        }
    }
    return negative ? -result : result;
}

} // namespace impl

BOOST_AUTO_TEST_CASE(unit_position) {
    BOOST_CHECK_EQUAL(impl::atoi("6"), 6);
}

BOOST_AUTO_TEST_CASE(tenth_position) {
    BOOST_CHECK_EQUAL(impl::atoi("45"), 45);
}

BOOST_AUTO_TEST_CASE(large_number) {
    BOOST_CHECK_EQUAL(impl::atoi("123456789"), 123456789);
}

BOOST_AUTO_TEST_CASE(negative_number) {
    BOOST_CHECK_EQUAL(impl::atoi("-876"), -876);
}

BOOST_AUTO_TEST_CASE(sign_in_wrong_position) {
    BOOST_CHECK_EQUAL(impl::atoi("72-56"), 0);
}

BOOST_AUTO_TEST_CASE(invalid) {
    BOOST_CHECK_EQUAL(impl::atoi("abcd"), 0);
}
# g++ -g -lboost_unit_test_framework -o atoi atoi.cpp && ./atoi --log_level=test_suite --report_level=short

Comments