• .net单元测试——常用测试方式(异常模拟、返回值测试、参数测试、数据库访问代码测试)


         最近在看.net单元测试艺术,我也喜欢单元测试,今天介绍一下如何测试异常、如何测试返回值、如何测试模拟对象的参数传递、如何测试数据库访问代码。单元测试框架使用的是NUnit,模拟框架使用的是:Rhino.Mocks。

    1.测试异常,可以直接对方法进行异常测试,也可以对模拟对象进行异常测试,但是,对模拟对象进行异常测试,很少用,所以,这里就介绍对方法的异常测试。请看如下代码,当用户名为空的时候,抛出异常。

         public bool Valid(string userName, string passWord)
            {
                if (string.IsNullOrEmpty(userName)) throw new ArgumentNullException("userName is null");
    
                var isValid = userName == "admin" && passWord == "123456";
    
                Log.Write(userName);
    
                return isValid;
            }

    测试代码如下:

          [Test]
           [ExpectedException(typeof(ArgumentNullException))]
           public void Vaild_Throw_Test()
            {
                MyLogin l = new MyLogin();
    
                l.Valid("", "123456");
            }

    这里需要特性“ExpectedException”,意思是期待抛出一个异常。这里不需要再进行断言了,抛出异常后,后面的代码也就不会执行了。

     

    2.测试返回值,这里主要讲测试模拟对象的返回值。这里用到了一个LastCall的一个类,比较常用,一些辅助测试的功能,都在该类中。测试代码如下:

            [Test]
            public void Valid_Return()
            {
                MockRepository mock = new MockRepository();
    
                var log = mock.DynamicMock<ILog>();
    
                using (mock.Record())
                {
                    log.WriteLog("admin");
                    LastCall.Return(0);
                }
            var returnValue = log.WriteLog("admin");
    
            Assert.AreEqual(returnValue, 0);
            }   
    

    3.测试模拟对象的参数传递,当调用模拟对象时,可能需要传递参数,如果参数的值不一至时,会导致测试失败,比如:我需要传递一个字符串,其中包含了一个GUID+UserName,这里GUID可能我们无法模拟,所以,测试参数时,只需要测试UserName就可以。

     方法代码如下:

        public bool Valid_Paramter(string userName, string passWord)
            {
                Log.Write(Guid.NewGuid() + userName);
    
                return userName == "admin" && passWord == "123456";
            }

    测试代码如下:

           [Test]
            public void Valid_Paramter()
            {
                MockRepository mock = new MockRepository();
    
                var log = mock.DynamicMock<ILog>();
    
                using (mock.Record())
                {
                    log.Write("admin");
    
                    LastCall.Constraints(Rhino.Mocks.Constraints.Text.Contains("admin"));
                }
            //这里代码如果不明白,可以看上一节,里面有说明。
                MyLogin login = new MyLogin();
    
                login.Log = log;
    
                var valid = login.Valid_Paramter("admin", "123456");
    
                Assert.AreEqual(valid, true);
    
                mock.VerifyAll();
            }
    

      这里只是测试模拟对象的参数传递。

     

    4.测试数据库访问代码,这里提供的方法是,执行完测试代码后,对数据库进行回滚。有两种实现方式,一种是使用Rollback特性,一种是使用TransactionScope类。其实,Rollback也使用TransactionScope类。

      1)   Rollback特性

      开始我以为Rollback是NUnit框架自带的一个特性,结果不是,需要自己编写代码,这里需要继承ITestAction接口,该接口包含BeforeTest方法和AfterTest方法。Rollback特性的代码如下:

      public class RollbackAttribute : Attribute, ITestAction
        {
            private TransactionScope transaction;
    
            public void BeforeTest(TestDetails testDetails)
            {
                transaction = new TransactionScope();
            }
    
            public void AfterTest(TestDetails testDetails)
            {
                transaction.Dispose();
            }
    
            public ActionTargets Targets
            {
                get { return ActionTargets.Test; }
            }
        }
    

      下面是被测试的代码,这里我用了EF框架,代码非常简单,向TitleInfo表中,写入数据,该表中只有一个字段,就是title字段。如果写入成功,则返回值大于0.

       public int Insert(string title)
            {
                testEntities db = new testEntities();
    
                var titleInfo = new TitleInfo()
                {
                    Title = title
                };
    
                db.TitleInfo.Add(titleInfo);
    
                return db.SaveChanges();
            }
    

      使用Rollback特性进行测试。

            [Test]
            [Rollback]
            public void Test_Insert()
            {
                DBLibrary db = new DBLibrary();
    
                var count = db.Insert("admin");
    
                Assert.True(count > 0);
            }  
    

       非常简单,加入Rollback特性即可,这里不会向数据库写入记录,但是测试会成功。

      2)   使用TransactionScope类测试数据访问层,该类可以实现数据库的事务操作,执行测试代码后,会对数据库的事务进行回滚,达到测试的目的,而不需要修改数据库的数据。测试代码如下:

        [TestFixture]
        class DBLibraryTest
        {
            TransactionScope socp;
    
            [SetUp]
            public void Init()
            {
                socp = new TransactionScope();
            }
    
            [TearDown]
            public void Close()
            {
                socp.Dispose();
            }
    
            [Test]
            public void Test_Insert()
            {
                DBLibrary db = new DBLibrary();
    
                var count = db.Insert("admin");
    
                Assert.True(count > 0);
            }
        }
    

      这里加入了TransactionScope类,在Test_Insert方法执行前,会先执行Init方法,执行完Test_Insert方法后,执行Close方法,对事务进行回滚。其实Rollback只是对TransactionScope进行了封装,通过NUnit框架,很方便的实现了数据库事务的回滚。

     

    总结:这里只是总结了常用的测试方法,如果大家还有其它的常见方法,可以分享一下,大家共同学习。

  • 相关阅读:
    .NET 去除一段文本中的HTML标记
    C#实现控件拖动窗口
    使用window.showModalDialog弹出窗口返回值(兼容IE、FF、chrome)
    IE浏览器报错出现stack overflow at line 0的解决办法
    用Python作GIS:原料篇
    winform 自定义控件:半透明Loading控件
    WPF 跟随鼠标动画 by wgscd
    C# 多线程 HTTP request
    VS2015 安装XAN
    C# 用QQ企业邮箱发邮件
  • 原文地址:https://www.cnblogs.com/xingzhang/p/Nunit_CommonTest.html
Copyright © 2020-2023  润新知