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

来源:互联网 发布:成都专业seo营销公司 编辑:程序博客网 时间:2024/05/20 08:25

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 0