VS2012 Unit Test —— 我对接口进行单元测试使用的技巧

 【题外话】

  对单元测试不熟悉的童鞋可参照我之前写过的两篇博文:

在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时就轻而易举的完成它的单元测试,后期开发效率与质量均得到保证。      

  编写完毕,借此抛砖引玉,希望得到您更好的意见,鲜花鸡蛋均欢迎。

posted @ 2013-08-18 17:34 dong.net 阅读(...) 评论(...) 编辑 收藏