[阅读笔记]Modern C++ Programming with Test-Driven Develpment chp2

81 篇文章 0 订阅
9 篇文章 0 订阅

1. 前言

最近突然对代码测试非常感兴趣, 学习了一些google test 框架的内容之后, 开始啃Modern C++ Programming with Test-Driven Develpment,ie, code better sleep better

工程代码地址: https://github.com/zhyh2010/DDTlearning
电子书资源: http://download.csdn.net/detail/zhyh1435589631/9672524

2. 主要内容

2.1 小结的一些东西

  1. chp 2 主要是手把手的带我们写了一个小程序, 涉及TDD, refactor等各种东西, 麻雀虽小五脏俱全
  2. 主要借助的是google mock 的测试框架, 我们这里顺手替换成了 google test, 也非常类似
  3. 每次先写测试代码, 测试不通过之后, 再考虑编写相应代码使得测试代码可以通过
  4. 每次写代码的时候, 为了让测试得以通过, 怎么方便怎么写, 根据不断的新的测试需求, 对代码不断重构 refactor
  5. TDD 先写测试再写功能代码, 测试(先写功能代码),效果一致, 不过如果是TDD 驱动的话, 可能测试用例会想的更全一些, 更加稳健
  6. 使用 DISABLED_ 前缀来使一个测试无效
  7. 除了用户需求之外, 还应该关注一些, 异常情况,非法输入的处理
  8. 单一职责SRP 的使用

2.2 经典语句

1.test list

Each test you write in TDD and get to pass represents a new, working piece of
behavior that you add to the system. Aside from getting an entire feature shipped,
your passing tests represent your best measure of progress. You name each test to

2.incrementalism
这个就非常类似软件工程中所谈及的敏捷开发的概念了, 小步伐, 快速更新迭代

We have two jobs: write a new test that describes the behavior, and change
our existing test to ensure it meets the spec.

A strength of TDD is its ability to let you move forward in the face of incomplete information and in its ability to let you correct earlier choices as new information
arises.

3.Thinking and TDD
利用测试驱动, 编写满足需求的代码

The cycle of TDD, once again in brief, is to write a small test, ensure it fails, get it to pass, review and clean up the design (including that of the tests), and ensure the tests all still pass

3. 相应的代码

SoundexTest.cpp

#include "gtest/gtest.h"
#include "Soundex.h"

class SoundexEncoding :public testing::Test{
public:
    Soundex soundex;
};

TEST_F(SoundexEncoding, RetainsSoleLetterOfOneLetterWord){
    auto encoded = soundex.encode("A");
    ASSERT_EQ(encoded, std::string("A000"));
}

TEST_F(SoundexEncoding, PadsWithZerosToEnsureThreeDigits){
    auto encoded = soundex.encode("I");
    ASSERT_EQ(encoded, std::string("I000"));
}

TEST_F(SoundexEncoding, ReplaceConsonantsWithAppropriateDigits){
    EXPECT_EQ(soundex.encode("Ab"), std::string("A100"));
    EXPECT_EQ(soundex.encode("Ac"), std::string("A200"));
    EXPECT_EQ(soundex.encode("Ad"), std::string("A300"));
    EXPECT_EQ(soundex.encode("Ax"), std::string("A200"));
    EXPECT_EQ(soundex.encode("A@"), std::string("A000"));
}

TEST_F(SoundexEncoding, ReplacesMultipleConsonantsWithDigits){
    ASSERT_EQ(soundex.encode("Acdl"), std::string("A234"));
}

TEST_F(SoundexEncoding, LimitsLengthToFourCharacters){
    ASSERT_EQ(soundex.encode("Dcdlb").length(), 4u);
}

TEST_F(SoundexEncoding, IgnoresVowelLikeLetters){
    ASSERT_EQ(soundex.encode("Baeiouhycdl"), std::string("B234"));
}

TEST_F(SoundexEncoding, CombinesDuplicateEncodings){
    ASSERT_EQ(soundex.encodedDigits('b'), soundex.encodedDigits('f'));
    ASSERT_EQ(soundex.encodedDigits('c'), soundex.encodedDigits('g'));
    ASSERT_EQ(soundex.encodedDigits('d'), soundex.encodedDigits('t'));

    ASSERT_EQ(soundex.encode("Abfcgdt"), std::string("A123"));
}

TEST_F(SoundexEncoding, UppercasesFirstLetter){
    ASSERT_EQ(soundex.encode("abcd").substr(0, 1), std::string("A"));
}

TEST_F(SoundexEncoding, IgnoreVowelLikeLetters){
    ASSERT_EQ(soundex.encode("BaAeEiIoOuUhHyYcdl"), std::string("B234"));
}

TEST_F(SoundexEncoding, CombinesDuplicateCodesWhen2ndLetterDuplicateslst){
    ASSERT_EQ(soundex.encode("Bbcd"), std::string("B230"));
}

TEST_F(SoundexEncoding, DoesNotCombineDuplicateEncodingsSeparatedByVowels){
    ASSERT_EQ(soundex.encode("Jbob"), std::string("J110"));
}

int main(int argc, char ** argv){
    ::testing::InitGoogleTest(&argc, argv);
    RUN_ALL_TESTS();

    system("pause");
    return 0;
}

Soundex.h

#ifndef _SOUNDEX_H_
#define _SOUNDEX_H_

#include <string>
#include <unordered_map>
#include <cctype>

class Soundex{
    static const size_t MaxCodeLength{ 4 };
    const std::string NotADigit{ "*" };

public:
    std::string encode(const std::string & word) const{
        return zeroPad(upperFront(head(word)) + tail(encodedDigits(word)));
    }

    std::string encodedDigits(char letter) const{
        const std::unordered_map<char, std::string> encodings{
            { 'b', "1" }, { 'f', "1" }, { 'p', "1" }, { 'v', "1" },
            { 'c', "2" }, { 'g', "2" }, { 'j', "2" }, { 'k', "2" },
            { 'q', "2" }, { 's', "2" }, { 'x', "2" }, { 'z', "2" },
            { 'd', "3" }, { 't', "3" },
            { 'l', "4" },
            { 'm', "5" }, { 'n', "5" },
            { 'r', "6" }
        };
        auto it = encodings.find(tolower(letter));
        return it == encodings.end() ? NotADigit : it->second;
    }

private:
    std::string upperFront(const std::string & string) const {
        return std::string(1, std::toupper(static_cast<unsigned char>(string.front())));
    }

    char lower(char c) const{
        return std::tolower(static_cast<unsigned char>(c));
    }

    std::string head(const std::string & word) const{
        return word.substr(0, 1);
    }

    std::string tail(const std::string & word) const{
        return word.substr(1);
    }

    void encodeHead(std::string & encoding, const std::string & word) const{
        encoding += encodedDigits(word.front());
    }

    void encodeLetter(std::string & encoding, char letter, char lastLetter) const{
        auto digit = encodedDigits(letter);
        if (digit != NotADigit && 
            (digit != lastDigit(encoding) || isVowel(lastLetter)))
            encoding += digit;
    }

    bool isVowel(char letter) const{
        return std::string("aeiouy").find(lower(letter)) != std::string::npos;
    }

    void encodeTail(std::string & encoding, const std::string & word) const{
        for (auto i = 1u; i < word.length(); i++){
            if (!isComplete(encoding))
                encodeLetter(encoding, word[i], word[i - 1]);           
        }
    }

    std::string encodedDigits(const std::string & word) const{
        std::string encoding;
        encodeHead(encoding, word);
        encodeTail(encoding, word);                 
        return encoding;
    }

    std::string lastDigit(const std::string & encoding) const{
        if (encoding.empty()) return NotADigit;
        return std::string(1, encoding.back());
    }

    bool isComplete(const std::string & encoding) const{
        return encoding.length() == MaxCodeLength;
    }

    std::string zeroPad(const std::string & word) const{
        auto zerosNeed = MaxCodeLength - word.length();
        return word + std::string(zerosNeed, '0');
    }
};

#endif // _SOUNDEX_H_
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Modern C++ Programming Cookbook by Marius Bancila English | 15 May 2017 | ASIN: B01MQDKPV8 | 590 Pages | AZW3 | 800.97 KB Over 100 recipes to help you overcome your difficulties with C++ programming and gain a deeper understanding of the working of modern C++ About This Book Explore the most important language and library features of C++17, including containers, algorithms, regular expressions, threads, and more, Get going with unit testing frameworks Boost.Test, Google Test and Catch, Extend your C++ knowledge and take your development skills to new heights by making your applications fast, robust, and scalable. Who This Book Is For If you want to overcome difficult phases of development with C++ and leverage its features using modern programming practices, then this book is for you. The book is designed for both experienced C++ programmers as well as people with strong knowledge of OOP concepts. What You Will Learn Get to know about the new core language features and the problems they were intended to solve Understand the standard support for threading and concurrency and know how to put them on work for daily basic tasks Leverage C++'s features to get increased robustness and performance Explore the widely-used testing frameworks for C++ and implement various useful patterns and idioms Work with various types of strings and look at the various aspects of compilation Explore functions and callable objects with a focus on modern features Leverage the standard library and work with containers, algorithms, and iterators Use regular expressions for find and replace string operations Take advantage of the new filesystem library to work with files and directories Use the new utility additions to the standard library to solve common problems developers encounter including string_view, any , optional and variant types In Detail C++ is one of the most widely used programming languages. Fast, efficient, and flexible, it is used to solve many problems. The latest versions of C++ have seen programmers change the way they code, giving up on the old-fashioned C-style programming and adopting modern C++ instead. Beginning with the modern language features, each recipe addresses a specific problem, with a discussion that explains the solution and offers insight into how it works. You will learn major concepts about the core programming language as well as common tasks faced while building a wide variety of software. You will learn about concepts such as concurrency, performance, meta-programming, lambda expressions, regular expressions, testing, and many more in the form of recipes. These recipes will ensure you can make your applications robust and fast. By the end of the book, you will understand the newer aspects of C++11/14/17 and will be able to overcome tasks that are time-consuming or would break your stride while developing. Style and approach This book follows a recipe-based approach, with examples that will empower you to implement the core programming language features and explore the newer aspects of C++.

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值