這份題目的需求是針對句子中每一個超過5個(含)進行反轉,並輸出反轉後的句子。
Codewars kata題目:Stop gninnipS My sdroW! TDD練習。
繼這周遇見91看見他那高強的功力進行重構程式後,對TDD的概念有更深的感覺,所以決定在每天有時間都去他強力推薦的Codewars裡找題目練習TDD
Codewars的題目大部分相較於單純,十分的適合練習TDD。
為什麼會選這題呢? 哦..因為他剛好自己跳出來的啊 我覺得看起來很簡單就做了
因為他看起來起來很好拆解,所以我把他拆成了以下幾個需求
- Split方法
- 字串長度判斷方法
- 反轉字串方法
- 字串串接方法
首先寫一個測試,輸入空字串,我們預期結果是空字串,其Test Code如下
[TestClass]
public class UnitTest1
{
[TestMethod]
public void Input_Empty_Should_Be_Empty()
{
var input = string.Empty;
var expected = string.Empty;
var actual = Kata.spinWords(input);
Assert.AreEqual(expected,actual);
}
}
一開始的Production Code如下,然後跑測試,跑完測試,出現了第一個紅燈
public class Kata
{
public static string spinWords(string input)
{
throw new NotImplementedException();
}
}
接著用最簡單的方式去讓他變成綠燈,Production Code 改成如下
public class Kata
{
public static string spinWords(string input)
{
return string.Empty;
}
}
再來我們綠燈之後,新增一個測試案例,輸入為aAAa,預期結果為aAAa
這個測試案例的目的是讓Production Code可以進行印出
其Test Code如下
public void Input_aAAa_Should_Be_aAAa()
{
var input = "aAAa";
var expected = "aAAa";
var actual = Kata.spinWords(input);
Assert.AreEqual(expected,actual);
}
將Production Code改成可以回傳自己
public class Kata
{
public static string spinWords(string input)
{
return input;
}
}
跑測試過了之後發現Test Code是可以進行重構的,於是重構了Test Code,其Code 以及 重構後的Test Code如下
[TestClass]
public class UnitTest1
{
[TestMethod]
public void Input_Empty_Should_Be_Empty()
{
spinResult(string.Empty,string.Empty);
}
[TestMethod]
public void Input_aAAa_Should_Be_aAAa()
{
spinResult("aAAa", "aAAa");
}
private static void spinResult(string input, string expected)
{
var actual = Kata.spinWords(input);
Assert.AreEqual(expected, actual);
}
}
重構完成了,我們就開始寫新的測試案例吧! 輸入Hello 預期結果是 olleH,其測試Code 如下,現在要新增測試案例變得十分簡便,不需要再往上copy paste 測試案例的code
所以新增的測試案例Code如下
這個測試案例的目的是實做一個針對字串反轉的方法。
public void Input_Hello_Should_Be_olleH()
{
spinResult("Hello","olleH");
}
首先先讓這個測試案例失敗,紅燈了,再開始改Production Code來完成反轉字串的方法,完成後亮綠燈,改完的Code 如下
public class Kata
{
public static string spinWords(string input)
{
if (input.Length > 4)
{
char[] inputArray = input.ToCharArray();
Array.Reverse(inputArray);
return new string(inputArray);
}
return input;
}
}
Prodcution Code 改完之後再新增一個測試案例,輸入 Hello World 預期結果為 olleH dlroW,其Test Code如下。
這個案例是直接split字串後在split後的字串進行處理,處理完成後再將它們Join起來
這邊我不小心跨太大步了,所以這邊要新增的測試應該要是只針對多個長度未超過4的字串作為測試案例(或其他)才會比較好,EX:input "this is a test. shoud" be "this is a test"
[TestMethod]
public void Input_Hello_World_Should_Be_olleH_dlroW()
{
spinResult("Hello World", "olleH dlroW");
}
這時候要讓Production Code去跑每一個個別的字串,所以要用string的Split()方法去針對超過長度4的字串做個別處理,處理完成後讓使用Split()方法後的字串陣列去做串接[string.Join()] (其中間都要有空白),code如下
public class Kata
{
public static string spinWords(string input)
{
string[] inputArray = input.Split();
for (int i = 0; i < inputArray.Length; i++)
{
char[] inputCharArray = inputArray[i].ToCharArray();
if (inputArray[i].Length > 4)
{
Array.Reverse(inputCharArray);
}
inputArray[i] = new string(inputCharArray);
}
return string.Join(" ",inputArray);
}
}
更改Production Code之後,我們將反轉字串的方法提取出來做並重構
public class Kata
{
public static string spinWords(string input)
{
string[] inputArray = input.Split();
for (int i = 0; i < inputArray.Length; i++)
inputArray[i] = reverseArray(inputArray[i].ToCharArray());
return string.Join(" ", inputArray);
}
private static string reverseArray(char[] inputArray)
{
if (inputArray.Length > 4)
Array.Reverse(inputArray);
return new string(inputArray);
}
}
接下來補上一些codewars上的測試資料進行測試,最後所有測試案例的Code如下
[TestClass]
public class UnitTest1
{
[TestMethod]
public void Input_Empty_Should_Be_Empty()
{
spinResult(string.Empty, string.Empty);
}
[TestMethod]
public void Input_aAAa_Should_Be_aAAa()
{
spinResult("aAAa", "aAAa");
}
[TestMethod]
public void Input_Hello_Should_Be_olleH()
{
spinResult("Hello", "olleH");
}
[TestMethod]
public void Input_Hello_World_Should_Be_olleH_dlroW()
{
spinResult("Hello World", "olleH dlroW");
}
[TestMethod]
public void Input_Welcome_Should_Be_emocleW()
{
spinResult("Welcome", "emocleW");
}
[TestMethod]
public void Input_Hey_fellow_warriors_Should_Be_Hey_wollef_sroirraw()
{
spinResult("Hey fellow warriors","Hey wollef sroirraw");
}
[TestMethod]
public void Input_This_is_a_test_Should_Be_This_is_a_test()
{
spinResult("This is a test","This is a test");
}
[TestMethod]
public void Input_This_is_another_test_Should_Be_This_is_rehtona_test()
{
spinResult("This is another test", "This is rehtona test");
}
[TestMethod]
public void Input_You_are_almost_to_the_last_test_Should_Be_You_are_tsomla_to_the_last_test()
{
spinResult("You are almost to the last test", "You are tsomla to the last test");
}
[TestMethod]
public void Input_Just_kidding_there_is_still_one_more_Should_Be_Just_gniddik_ereht_is_llits_one_more()
{
spinResult("Just kidding there is still one more", "Just gniddik ereht is llits one more");
}
private static void spinResult(string input, string expected)
{
var actual = Kata.spinWords(input);
Assert.AreEqual(expected, actual);
}
}
這一次的TDD練習,在最後那Hello World測試案例,一次時做太多了,下一次要注意思考好跨得步伐大小,這一次跨太大步就發生了一堆東西搞在一起的問題,這是不應該發生的。
在完成重構Production Code 之後 原以為這個Code 已經算是蠻精簡的了,但把這份Code上傳到Codewars後,看到別人寫出來的其他Solution就發現有更精簡,也可以結合Linq的方式去完成這份程式,這讓我感到很興奮!! 因為我完全沒想到有這種作法!
這裡是本文的commit history
91在介紹codewars以及跟我私聊幾句時說了下面這段話
我們需要找到一種持續給自己回饋的方式,才能持續改善
所以 scrum 裡面有 iteration (迭代)
所以有 retrospective
一切都是持續改善的基本要素