初次使用單元測(cè)試后的體會(huì)
我們搞開發(fā)的往往覺得自己寫的代碼沒問題,用不著測(cè)試,以前,我也這么認(rèn)為,覺得測(cè)試?yán)速M(fèi)時(shí)間,也就沒仔細(xì)研究過測(cè)試。
最近,閑來想試試單元測(cè)試,結(jié)合之前的編程經(jīng)驗(yàn),發(fā)現(xiàn),單元測(cè)試至少是保證軟件質(zhì)量的最佳方式之一。一波一波程序員開發(fā)、維護(hù)一個(gè)產(chǎn)品,程序員之間的差別太大了,就像“明顯沒有錯(cuò)誤”和“沒有明顯錯(cuò)誤”的區(qū)別,怎么來保證產(chǎn)品在不斷迭代中的質(zhì)量,保留里面正確的部分,去掉bug呢?架構(gòu)設(shè)計(jì)里面講究面向接口,單元測(cè)試就能起到接口的作用。
通過單元測(cè)試的類,它的行為是符合當(dāng)初單元設(shè)計(jì)的目標(biāo)的。只要編寫單元測(cè)試時(shí),從多方面檢驗(yàn)類的行為,就能確保在這樣的情景下,類是符合設(shè)計(jì)的。在Vistual Studio中,最簡(jiǎn)單的單元測(cè)試就是使用本身自帶的功能(不需要從網(wǎng)上找NUnit的程序集,直接在項(xiàng)目上引用"Microsoft.VisualStudio.QualityTools.UnitTestFramework"程序集就ok了)。還有另外一個(gè)好處,是方便調(diào)試。單元測(cè)試項(xiàng)目可以在測(cè)試運(yùn)行時(shí),對(duì)被測(cè)試類下斷點(diǎn),非常節(jié)約調(diào)試時(shí)間。
我是這么做的,單元測(cè)試的代碼放到獨(dú)立的項(xiàng)目中去,引用要測(cè)試的項(xiàng)目,在被測(cè)試項(xiàng)目中添加Assembly特性如下:
[assembly: InternalsVisibleTo("Projky.UnitTests")]
這樣,單元測(cè)試就能對(duì)被測(cè)試項(xiàng)目中internal修飾符的類可見,又不破壞程序集的可見性。
舉一個(gè)簡(jiǎn)單的需求,要將如“30d9132169211a45”或者“30-D9-13-21-69-21-1A-45”或者“30 D9 13 21 69 21 1A 45”這樣的16進(jìn)制字符串轉(zhuǎn)換為Byte[]數(shù)組。設(shè)計(jì)了一個(gè)ByteString的類來實(shí)現(xiàn)需求。
internal class ByteString { public static Byte[] ConverterToBytes(string value) { if (value.IndexOf("-") > -1) { value = value.Replace("-", ""); } else if (value.IndexOf(" ") > -1) { value = value.Replace(" ", ""); } Debug.Assert(value.Length % 2 == 0, "Invalid byte string length."); List<Byte> list = new List<Byte>(value.Length / 2); for (int i = 0; i < value.Length; i += 2) { int bHi = GetInteger(value[i]); int bLow = GetInteger(value[i + 1]); Byte temp = (Byte)(bHi << 4 | bLow); list.Add(temp); } return list.ToArray(); } static int GetInteger(char ch) { if (Char.IsDigit(ch)) { return ch - '0'; } int value = 10; switch (ch) { case 'a': case 'A': value = 10; break; case 'b': case 'B': value = 11; break; case 'c': case 'C': value = 12; break; case 'd': case 'D': value = 13; break; case 'e': case 'E': value = 14; break; case 'f': case 'F': value = 15; break; default: throw new NotSupportedException(ch.ToString() + " is not valid char."); } return value; } } |
那么,簡(jiǎn)單驗(yàn)證該類的行為(接口)可以編寫下面的測(cè)試類:
[TestClass] public class ByteStringTest { [TestMethod] public void ConverterToBytes() { string input = "30d9132169211a45"; Byte[] bytes = ByteString.ConverterToBytes(input); Assert.IsTrue(bytes.Length == input.Length / 2); Assert.IsTrue(bytes[0] == 0x30); Assert.IsTrue(bytes[1] == 0xd9); Assert.IsTrue(bytes[2] == 0x13); Assert.IsTrue(bytes[3] == 0x21); Assert.IsTrue(bytes[4] == 0x69); Assert.IsTrue(bytes[5] == 0x21); Assert.IsTrue(bytes[6] == 0x1a); Assert.IsTrue(bytes[7] == 0x45); input = "30-D9-13-21-69-21-1A-45"; bytes = ByteString.ConverterToBytes(input); Assert.IsTrue(bytes.Length == 8); Assert.IsTrue(bytes[0] == 0x30); Assert.IsTrue(bytes[1] == 0xd9); Assert.IsTrue(bytes[2] == 0x13); Assert.IsTrue(bytes[3] == 0x21); Assert.IsTrue(bytes[4] == 0x69); Assert.IsTrue(bytes[5] == 0x21); Assert.IsTrue(bytes[6] == 0x1a); Assert.IsTrue(bytes[7] == 0x45); input = "30 D9 13 21 69 21 1A 45"; bytes = ByteString.ConverterToBytes(input); Assert.IsTrue(bytes.Length == 8); Assert.IsTrue(bytes[0] == 0x30); Assert.IsTrue(bytes[1] == 0xd9); Assert.IsTrue(bytes[2] == 0x13); Assert.IsTrue(bytes[3] == 0x21); Assert.IsTrue(bytes[4] == 0x69); Assert.IsTrue(bytes[5] == 0x21); Assert.IsTrue(bytes[6] == 0x1a); Assert.IsTrue(bytes[7] == 0x45); } } |
如果單元測(cè)試運(yùn)行失敗,例如Assert.IsTrue()方法中,參數(shù)為False,則在VS中會(huì)拋異常,這樣,就知道哪里不正確了。
注意用[TestClass]標(biāo)記作為單元測(cè)試承載的類,是public可見性,而里面單個(gè)的獨(dú)立測(cè)試方法,則采用[TestMethod]標(biāo)記,同樣是public可見性。
在Visual Studio里面還有一個(gè)技巧,按Ctrl + R,A可以自動(dòng)運(yùn)行單元測(cè)試項(xiàng)目。如果被測(cè)試類有斷點(diǎn)的話,測(cè)試到該位置時(shí),也會(huì)斷下來。
posted on 2014-08-21 09:42 順其自然EVO 閱讀(157) 評(píng)論(0) 編輯 收藏 所屬分類: 測(cè)試學(xué)習(xí)專欄