TDD 之 Dojo coding

  dojo和kata的练习记录:
  进入 http://cyber-dojo.org/

  由一个人进行 setup a default practice,然后创建:

  这里支持各种语言和各种测试框架,这里我们选择C++和GoogleTest

  这里是选择一个题目进行联系,我们选择“网球记分规则”来练习。

  成功之后,他会给每个人都分配一个动物头像,下面的三个圈,红色代表case执行失败,黄色代表编译失败,绿色代表case执行通过。

  第一个创建的人,把生成的url中的http://cyber-dojo.org/kata/edit/52E43B0082?avatar=raccoon “52E43B0082” 提取出即可,这样其他人可以通过enter a practice进入:

  所有人进入后,我们可以通过首页的看到所有人的一个状态:

  每个人进入后,都是如下界面:

  这就是我们用来练习的IDE

   默认会帮你生成一个失败的case,我们点击上方的test就会失败。

  于是我们需要修改case,让它变为成功状态,变为绿色。

  这是我修改成功后,点击test之后,得到了绿色的小球,然后再点击绿色小球的结果,这里可以看到你每次的修改。

  后面的流程基本就是写一个case,然后再实现一个逻辑的代码,然后在run。如此反复,我第一次完成的时候的代码:

  先看测试代码:

#include "hiker.hpp"
#include <gtest/gtest.h>

using namespace ::testing;

TEST(Hiker, player0_0)
{
    ASSERT_EQ("Love-All", score(0, 0));
}
TEST(Hiker, player1_1)
{
    ASSERT_EQ("Fifteen-All", score(1, 1));
}
TEST(Hiker, player2_2)
{
    ASSERT_EQ("Thirty-All", score(2, 2));
}
TEST(Hiker, player0_1)
{
    ASSERT_EQ("Love-Fifteen", score(0, 1));
}
TEST(Hiker, player1_0)
{
    ASSERT_EQ("Fifteen-Love", score(1, 0));
}
TEST(Hiker, player1_2)
{
    ASSERT_EQ("Fifteen-Thirty", score(1, 2));
}
TEST(Hiker, player3_1)
{
    ASSERT_EQ("Forty-Fifteen", score(3, 1));
}
TEST(Hiker, player0_3)
{
    ASSERT_EQ("Love-Forty", score(0, 3));
}
TEST(Hiker, player4_4)
{
    ASSERT_EQ("Deuce", score(4, 4));
}
TEST(Hiker, player5_4)
{
    ASSERT_EQ("Advantage Player1", score(5, 4));
}
TEST(Hiker, player4_5)
{
   ASSERT_EQ("Advantage Player2", score(4, 5));
}
TEST(Hiker, player6_4)
{
   ASSERT_EQ("Win for Player1", score(6, 4));
}
TEST(Hiker, player4_6)
{
   ASSERT_EQ("Win for Player2", score(4, 6));
}

  再看业务代码

#include "hiker.hpp"
 
string score(int p1, int p2)
{
    string so[4]={"Love","Fifteen","Thirty","Forty"};
    
    cout<<p1<<p2<<endl;
    if (p1 < 4 && p2 < 4)
    {
        if (p1==0 && p2==0)
        {
            return "Love-All";
        }
        else if (p1==1 && p2==1)
        {
            return "Fifteen-All";
        }
        else
        {
            return so[p1]+"-"+so[p2];
        }
    }
    else
    {
        if (p1==p2)
        {
            return "Deuce";
        }
        int cha = p1-p2;
        if (cha>0 && cha<2)
        {
            return "Advantage Player1";
        }
        else if(cha>1)
        {
            return  "Win for Player1";
        }
        else if(cha<0 && cha>-2)
        {
            return  "Advantage Player2";
        }
        else if(cha<-1)
        {
            return  "Win for Player2";
        }
    }
    return "hello world";
}

  是不是看起来逻辑好乱啊。没错我也是这样的感觉,特别想重构,一般说到重构,很多人心有余悸,没关系,我们有测试用例不用担心。 

  重构完成的代码和测试用例:

#include "hiker.hpp"

string score(int p1, int p2)
{
    string s_score[4]={"Love","Fifteen","Thirty","Forty"};
    string s_same[4]={"Love-All","Fifteen-All","Thirty-All","Deuce"};
    map<int,string> m_res;
    m_res.insert(pair<int, string>(1, "Advantage Player1"));
    m_res.insert(pair<int, string>(2, "Win for Player1"));
    m_res.insert(pair<int, string>(-1, "Advantage Player2"));
    m_res.insert(pair<int, string>(-2, "Win for Player2"));
           
    cout<<p1<<p2<<endl;
    
    // 处理相等的情况
    if (p1 == p2) 
    {
        if (p1 > 2)
            return s_same[3];
        return s_same[p1];
    }
    
    // 处理赢球数都在3以下的情况
    if (p1 < 4 && p2 < 4)
    {
        return s_score[p1]+"-"+s_score[p2];
    }
    
    // 处理赢球数都在3以上的情况
    else
    {
        return m_res[p1-p2];
     
    }
    return "error";
}

  可以看到我一共提交了48次

  大家的结果 http://cyber-dojo.org/dashboard/show/D9D934A59E:

 

  通过这次Dojo Coding,总结如下:

    1、先写case,再实现代码;

    2、每实现一个功能,run一次测试代码;

    3、重构的时候,每个小的单元重构一次,run一次测试代码。

  这样就可以保证,你在重构完成之后,所有的功能是可以通过的。也就是TDD的思想。

 

posted @ 2017-10-31 19:14  胖喵~  Views(1320)  Comments(0Edit  收藏  举报