大學終於要邁入尾聲了,工作也找到了相對較好的,現在就差畢業設計了。我一直堅信着這樣的原則:當面臨很多選擇時,選擇最難的那一個,所以我選擇了室內導盲系統設計。其實這也不是最難的,只是我以前沒有做過類似的工作,其他多多少少都有涉及,所以特地選擇了這個。
說難其實也不難,因為硬件已經做好了,我要做的就是設計軟件。軟件設計的方法有很多種,還是秉持着那條原則:選擇最難的那個,所以我選擇了測試驅動開發的方式。
在寫這篇文章的時候,我的室友打機打得正酣,而我則在一邊忙着敲代碼,這時突然意識到,為啥他們能夠接受那樣低水平的工作而沒有任何抱怨,甚至在當初連做選擇都沒有就接受了,然后就一直拼命的打機消磨時光,除了一個一出生就是官二代,富二代之外,其他還是必須要找工作,並且一找到工作就馬上接受,哪怕這份工作的待遇非常低。原因非常簡單:見識的局限性。我已經出來實習工作了,見識到公司里有些人也是這樣的四個字:混吃等死。當我意識到這點的時候,是渾身打顫:為啥有些人以后的發展是那樣子,有些人以后是這樣子,除開一些無法改變的原因之外,最根本的就是他們骨子里就接受了這樣的事實:我就是只能找到這樣的工作,這樣的工作已經很好了。這就是所謂的認命。
明白到這點之后,我更加慶幸自己當初在找到第一份工作的時候還是有繼續找,直到找到一家在該行業也算是巨頭的公司並且通過他們的面試。就算自己現在的技術水平很菜,就算自己現在寫的代碼還是很爛,但我們還是要一直堅持在最前線,一直向上,也許,在前方,就有不一樣的風景在等着我們。
所謂的測試驅動開發思想非常簡單,就是在編寫具體的代碼前,先編寫測試代碼,然后想辦法讓自己的代碼通過測試。思想非常簡單,但實現起來卻不容易,除開工具,就是自己所寫的測試單元可以說是基於自己的想象,因為沒有任何具體的實現,只有測試用例。有具體的輸入輸出的測試用例還是比較好寫,但如果是更加抽象的測試用例,該測試什么都是個問題。但這並不阻止我去編寫測試單元,因為我深深明白到一件事:人之所以選擇混吃等死,是因為他們根本就不知道在這上面的風景到底是怎樣。所以,故意去使用一些高級的技術並不是壞事,它會讓我們明白到原來還有這樣的東西,就算嘗試是失敗的,但至少我們也明白到這東西大概是什么樣子的,並且在這個嘗試中學到很多東西。
第一個測試模塊就是測試手機發送連接指令還有接收響應指令。
指令的格式已經是固定的,所以這不是難事,第一個測試可以這樣測試:
public void test{ byte[] byteArr = {}; byte[] command = mCommand.getCommand(); for(int i = 0, length = byteArr.length; i < length; ++i){ assertEquals(byteArr[i], command[i]); } }
為了讓這個測試通過,我們必須建立一個類Command:
public class Command{ private byte[] mCommandByte = {}; public byte[] getCommand(){ return mCommandByte; } }
第一個測試通過!在通過這個測試的時候,我們建立了一個用於存儲指令的類Command,它的第一個職責就是返回相關的指令。
我們接着編寫測試單元。
發送指令是向整個局域網所有可能的網關發送,每發送完一條,指令的序號就會加1,等到99后又從0開始。根據這樣的特性,我們可以這樣寫測試:
public void test(){ Gateway gate = new Gateway(); List<byte[]> commandList = new ArrayList<byte[]>(); for(int i = 0; i < 100; ++i){ byte[] command = {(byte)i, ...}; commandList.add(command); } commandList.add(new byte[]{(byte)0, ...}); for(int i = 0; i < 101; ++i){ byte[] response = mCommand.send(gate); byte[] bytes = bytesList.get(i); assertEquals(bytes[0], response[0]); } }
這里涉及到新的對象:網關Gate,所以需要創建一個新的類:Gataway。Gateway在接收到Command發送的指令后,會返回一條響應指令,該指令的序號和接收到的指令是一樣的。
public class Gateway { private byte[] RESPONSE_COMMAND = {}; public byte[] response(byte[] command) { RESPONSE_COMMAND[0] = command[0]; return RESPONSE_COMMAND; }
這里Command多了一個新的職責:send():
public byte[] send(Gateway gate) { byte[] response = gate.response(CONNECT_COMMAND); CONNECT_COMMAND[0]++; if (CONNECT_COMMAND[0] > (byte) 99) { CONNECT_COMMAND[0] = (byte) 0; } return response; }
就是這樣,我們簡單的通過兩個測試就建立了兩個基本的類型:Command和Gateway,並且確定了它們的基本行為,當然,在隨后更多的測試中,這兩個類會添加更多測試,甚至是被證明是無用的而被刪除掉,都有可能。
測試驅動開發就是利用預先編寫好的測試代碼驗證自己編寫de代碼是否正確,如果不符合測試,說明代碼存在問題,必須修改直到測試通過。當然,這種方式要求我們一開始編寫的測試代碼必須是正確的,這比編寫代碼需要更多的經驗和技術要求,幸好,測試代碼也是可以修改的,只要驗證測試代碼不符合目前所有測試的用例情況,這個在嘗試各種努力仍無法讓測試通過時,可以考慮下測試的正確性。