VS2012 Unit Test —— 我對介面進行單元測試使用的技巧

dong.net發表於2013-08-18

 【題外話】

  對單元測試不熟悉的童鞋可參照我之前寫過的兩篇博文:

在Visual Studio 2012使用單元測試》、

VS2012 單元測試之泛型類(Generics Unit Test)》。
  

  以下Demo將使用我已寫好的一些關於單元測試的類庫(已放至 https://idletest.codeplex.com/ 

,其用了大量的匿名方法,同樣不熟悉的可參照我上一篇博文《委託的N種寫法,你喜歡哪種?

 

【進入正題】

   與其說對介面測試還不如說針對抽象測試,也是我個人比較喜歡的編碼步驟:編寫介面(面向抽象)=>單元測試=>實現。

  OK here we go...

  首先假設有如下介面(這也是從我的程式碼中提取出來的)

    public interface ITextFormatter
    {
        /// <summary>
        /// 根據指定格式字串獲取物件
        /// </summary>
        T GetObject<T>(string formatString);

        /// <summary>
        /// 將物件轉化為指定格式字串
        /// </summary>
        string GetString(object obj);
    }

 

  那麼接下來我要做的並不是馬上去實現它,而是測試先行,我將編寫如下測試程式碼

    public abstract class BaseFormatterTest
    {
        protected abstract ITextFormatter formatter
        {
            get;
        }
        
        /// <summary>
        ///GetObject 的測試
        ///</summary>
        public void GetObjectTestHelper<T>()
        {
            AssertCommon.AssertIsNull<string, T>(TestCommon.GetEmptyStrings(), true, (string strTemp) => {
                return formatter.GetObject<T>(strTemp);
            });

            EntityParameter ep = new EntityParameter(123);
            string str = formatter.GetString(ep);
            EntityParameter actual = formatter.GetObject<EntityParameter>(str);
            Assert.IsNotNull(actual);
            Assert.AreEqual<int>(123, actual.Data);
        }

        public virtual void GetObjectTest()
        {            
            GetObjectTestHelper<GenericParameterHelper>();
        }

        /// <summary>
        ///GetString 的測試
        ///</summary>
        public virtual void GetStringTest()
        {
            AssertCommon.AssertEmpty<string>(formatter.GetString(null));

            AssertCommon.AssertEmpty<string>(formatter.GetString(new object()), false);

            string actual = formatter.GetString(new EntityParameter(12));
            AssertCommon.AssertEmpty<string>(actual, false);
            EntityParameter entity = formatter.GetObject<EntityParameter>(actual);
            Assert.AreEqual<int>(12, entity.Data);
        }
針對介面測試抽象基類

值得注意的是以上方法中包含了一個叫做AssertCommon類,這個是我自己定義的,原始碼在 https://idletest.codeplex.com/。

  我現在通過Xml序列化實現字串與物件的相互轉化,所以我繼承這個基類來編寫具體的測試,當然此時的測試程式碼就很簡單了。

    /// <summary>
    ///這是 ITextFormatterTest 的測試類,旨在
    ///包含所有 ITextFormatterTest 單元測試
    ///</summary>
    [TestClass()]
    public class XmlFormatterTest : BaseFormatterTest
    {
        [TestMethod()]
        public override void GetObjectTest()
        {
            base.GetObjectTest();
        }

        /// <summary>
        ///GetString 的測試
        ///</summary>
        [TestMethod]
        public override void GetStringTest()
        {
            base.GetStringTest();
        }

        protected override ITextFormatter formatter
        {
            get { return new XmlFormatter(); }
        }
    }

  完成測試編碼後開始實現具體程式碼,我這裡將建立一個抽象基類和一個子類去實現需要的功能

    public abstract class BaseFormatter
    {
        private Encoding encoding;
        public Encoding Encoding
        {
            get { return this.encoding; }
        }

        public BaseFormatter(Encoding encoding)
        {
            this.encoding = encoding;
        }
    }
    public class XmlFormatter : BaseFormatter, ITextFormatter
    {
        public XmlFormatter() : base(Encoding.Default) { }

        public XmlFormatter(Encoding encoding) : base(encoding) { }

        /// <summary>
        /// 將物件序列化為XML格式字串
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        public string GetString(object obj)
        {
            string result = string.Empty;
            if (obj ==null)
            {
                return result;
            }

            XmlSerializer serializer =new XmlSerializer(obj.GetType());            
            using (MemoryStream stream =new MemoryStream())
            {
                serializer.Serialize(stream, obj);
                byte[] buffer = stream.ToArray();
                result = this.Encoding.GetString(buffer);
                stream.Close();
            }

            return result;
        }

        ///<summary>
        /// 將XML格式字串轉化為物件
        ///</summary>
        public T GetObject<T>(string xmlString)
        {
            T obj = default(T);
            if (string.IsNullOrEmpty(xmlString))
            {
                return obj;
            }

            XmlSerializer serializer =new XmlSerializer(typeof(T));
            using (MemoryStream stream = new MemoryStream(this.Encoding.GetBytes(xmlString)))
            {
                obj = (T)serializer.Deserialize(stream);
                stream.Close();
            }

            return obj;
        }
    }

整個過程就這樣子,當然中間肯定執行多次測試來即時修正編碼過程中的錯誤。篇幅有限,我在這裡並沒有編寫建構函式的測試方法。

   

【後話】

  如此一來以後再新增對介面的更多實現時,保證了不再需要編寫大量重複的測試程式碼,例如再增加類JsonFormatter時就輕而易舉的完成它的單元測試,後期開發效率與質量均得到保證。      

  編寫完畢,藉此拋磚引玉,希望得到您更好的意見,鮮花雞蛋均歡迎。

相關文章