大学终于要迈入尾声了,工作也找到了相对较好的,现在就差毕业设计了。我一直坚信着这样的原则:当面临很多选择时,选择最难的那一个,所以我选择了室内导盲系统设计。其实这也不是最难的,只是我以前没有做过类似的工作,其他多多少少都有涉及,所以特地选择了这个。
说难其实也不难,因为硬件已经做好了,我要做的就是设计软件。软件设计的方法有很多种,还是秉持着那条原则:选择最难的那个,所以我选择了测试驱动开发的方式。
在写这篇文章的时候,我的室友打机打得正酣,而我则在一边忙着敲代码,这时突然意识到,为啥他们能够接受那样低水平的工作而没有任何抱怨,甚至在当初连做选择都没有就接受了,然后就一直拼命的打机消磨时光,除了一个一出生就是官二代,富二代之外,其他还是必须要找工作,并且一找到工作就马上接受,哪怕这份工作的待遇非常低。原因非常简单:见识的局限性。我已经出来实习工作了,见识到公司里有些人也是这样的四个字:混吃等死。当我意识到这点的时候,是浑身打颤:为啥有些人以后的发展是那样子,有些人以后是这样子,除开一些无法改变的原因之外,最根本的就是他们骨子里就接受了这样的事实:我就是只能找到这样的工作,这样的工作已经很好了。这就是所谓的认命。
明白到这点之后,我更加庆幸自己当初在找到第一份工作的时候还是有继续找,直到找到一家在该行业也算是巨头的公司并且通过他们的面试。就算自己现在的技术水平很菜,就算自己现在写的代码还是很烂,但我们还是要一直坚持在最前线,一直向上,也许,在前方,就有不一样的风景在等着我们。
所谓的测试驱动开发思想非常简单,就是在编写具体的代码前,先编写测试代码,然后想办法让自己的代码通过测试。思想非常简单,但实现起来却不容易,除开工具,就是自己所写的测试单元可以说是基于自己的想象,因为没有任何具体的实现,只有测试用例。有具体的输入输出的测试用例还是比较好写,但如果是更加抽象的测试用例,该测试什么都是个问题。但这并不阻止我去编写测试单元,因为我深深明白到一件事:人之所以选择混吃等死,是因为他们根本就不知道在这上面的风景到底是怎样。所以,故意去使用一些高级的技术并不是坏事,它会让我们明白到原来还有这样的东西,就算尝试是失败的,但至少我们也明白到这东西大概是什么样子的,并且在这个尝试中学到很多东西。
第一个测试模块就是测试手机发送连接指令还有接收响应指令。
指令的格式已经是固定的,所以这不是难事,第一个测试可以这样测试:
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代码是否正确,如果不符合测试,说明代码存在问题,必须修改直到测试通过。当然,这种方式要求我们一开始编写的测试代码必须是正确的,这比编写代码需要更多的经验和技术要求,幸好,测试代码也是可以修改的,只要验证测试代码不符合目前所有测试的用例情况,这个在尝试各种努力仍无法让测试通过时,可以考虑下测试的正确性。