测试技术之.NET单元测试的艺术-3.测试代码
白羽 2019-01-07 来源 :网络 阅读 979 评论 0

摘要:本文将带你了解测试技术.NET单元测试的艺术-3.测试代码,希望对大家学测试技术有所帮助。

    本文将带你了解测试技术.NET单元测试的艺术-3.测试代码,希望对大家学测试技术有所帮助。




   

  一、测试层次和组织

  1.1   测试项目的两种目录结构

  (1)集成测试和单元测试在同一个项目里,但放在不同的目录和命名空间里。基础类放在单独的文件夹里。

      

  (2)集成测试和单元测试位于不同的项目中,有不同的命名空间。

       

  实践中推荐使用第二种目录结构,因为如果我们不把这两种测试分开,人们可能就不会经常地运行这些测试。既然测试都写好了,为什么人们不愿意按照需要运行它们呢?一个原因是:开发人员有可能懒得运行测试,或者没有实践运行测试。

  1.2   构建绿色安全区

  将集成测试和单元测试分开放置,其实就给团队的开发人员构建了绿色安全区,这个区只包含单元测试。

  因为集成测试的本质决定了它运行时间较长,开发人员很有可能每天运行多次单元测试,较少运行集成测试。

      

  单元测试全部通过至少可以使开发人员对代码质量比较有信心,专注于提高编码效率。而且我们应该将测试自动化,编写每日构建脚本,并借助持续集成工具帮助我们自动执行这些脚本。

  1.3   将测试类映射到被测试代码

  (1)将测试映射到项目

  创建一个测试项目,用被测试项目的名字加上后缀.UnitTests来命名。

  例如:Manulife.MyLibrary   → Manulife.MyLibrary.UnitTests 和   Manulife.MyLibrary.IntegrationTests,这种方法看起来简单直观,开发人员能够从项目名称找到对应的所有测试。

  (2)将测试映射到类

  ①   每个被测试类或者被测试工作单元对应一个测试类:LogAnalyzer →   LogAnalyzer.UnitTests

  ②   每个功能对应一个测试类:有一个LoginManager类,测试方法为ChangePassword(这个方法测试用例特别多,需要单独放在一个测试类里边)   → 创建两个类 LoginManagerTests 和   LoginManagerTests-ChangePassword,前者只包含对ChangePassword方法的测试,后者包含该类其他所有测试。

  (3)将测试映射到具体的工作单元入口

  测试方法的命名应该有意义,这样人们可以很容易地找到所有相关的测试方法。

  这里,回归一下第一篇中提到的测试方法名称的规范,一般包含三个部分:[UnitOfWorkName]_[ScenarioUnderTest]_[ExpectedBehavior]

  1.UnitOfWorkName  被测试的方法、一组方法或者一组类

  2。Scenario  测试进行的假设条件,例如“登入失败”,“无效用户”或“密码正确”等

  3.ExpectedBehavior  在测试场景指定的条件下,你对被测试方法行为的预期

  示例:IsValidFileName_BadExtension_ReturnsFalse,IsValidFileName_EmptyName_Throws   等

  1.4 注入横切关注点

  当需要处理类似时间管理、异常或日志的横切关注点时,使用它们的地方会非常多,如果把它们实现成可注入的,产生的代码会很容易测试,但却很难阅读和理解。这里我们来看一个例子,假设应用程序使用当前时间进行写日志,相关代码如下:

  public   static class   TimeLogger

  {

  public static   string CreateMessage(string   info)

  {

  return   DateTime.Now.ToShortDateString() + " " +   info;

  }

  }

   


  为了使这段代码容易测试,如果使用之前的依赖注入技术,那么我们需要创建一个ITimeProvider接口,还必须在每个用到DateTime的地方使用到这个接口。这样做非常耗时,实际上,还有更直接的方法解决这个问题。

  Step1.创建一个名为SystemTime的定制类,在所有的产品代码里边使用这个定制类,而非标准的内建类DateTime。

     

   public   class SystemTime

  {

  private   static DateTime _date;

  public static void Set(DateTime   custom)

  {

  _date =   custom;

  }

  public static void   Reset()

  {

  _date =   DateTime.MinValue;

  }

  public   static DateTime   Now

  {

  get

  {

  //   如果设置了时间,SystemTime就返回假时间,否则返回真时间

  if (_date !=   DateTime.MinValue)

  {

  return   _date;

  }

  return   DateTime.Now;

  }

  }

  }

 

   


  阅读这段代码,其中有一个小技巧:SystemTime类提供一个特殊方法Set,它会修改系统中的当前时间,也就是说,每个使用这个SystemTime类的人看到的都是你指定的日期和时间。有了这样的代码,每个使用这个SystemTime类的人看到的都会是你指定的日期和时间。

  Step2.在测试项目中使用SystemTime进行测试。

  [TestFixture]

  public   class   TimeLoggerTests

  {

  [Test]

  public   void   SettingSystemTime_Always_ChangesTime()

  {

  SystemTime.Set(new   DateTime(2000, 1, 1));

  string output =   TimeLogger.CreateMessage("a");

  StringAssert.Contains("2000/1/1",   output);

  }

  ///   <summary>

  ///   在每个测试结束时重置日期

  ///   </summary>

  [TearDown]

  public   void   AfterEachTest()

  {

  SystemTime.Reset();

  }

  }

   


  在测试中,我们首先假定设置一个日期,然后进行断言。并且借助TearDown方法,确保当前测试不会改变其他测试的值。

  Note   : 这样做的好处就在于不用注入一大堆接口,我们所付出的代价仅仅在于在测试类中加入一个简单的[TearDown]方法,确保当前测试不会改变其他测试的值。

  1.5   使用继承使测试代码可重用

  推荐大家在测试代码中使用继承机制,通过实现基类,可以较好地展现面向对象的魔力。在实践中,一般有三种模式会被使用到:

  (1)抽象测试基础结构类模式

  ///   <summary>

  /// 测试类集成模式

  ///   </summary>

  [TestFixture]

  public   class BaseTestsClass

  {

  ///   <summary>

  /// 重构为通用可读的工具方法,由派生类使用

  ///   </summary>

  ///   <returns>FakeLogger</returns>

  public   ILogger FakeTheLogger()

  {

  LoggingFacility.Logger   = Substitute.For<ILogger>();

  return   LoggingFacility.Logger;

  }

  [TearDown]

  public   void ClearLogger()

  {

  //   测试之间要重置静态资源

  LoggingFacility.Logger =   null;

  }

  }

  [TestFixture]

  public   class LogAnalyzerTests : BaseTestsClass

  {

  [Test]

  public   void   Analyze_EmptyFile_ThrowsException()

  {

  //   调用基类的辅助方法

  FakeTheLogger();

  LogAnalyzer   analyzer = new   LogAnalyzer();

  analyzer.Analyze("myemptyfile.txt");

  //   测试方法的其余部分

  }

  }

   


  使用此模式要注意继承最好不要超过一层,如果继承层数过多,不仅可读性急剧下降,编译也很容易出错。


   
                   

本文由职坐标整理并发布,希望对同学们有所帮助。了解更多详情请关注职坐标软件测试之测试技术频道!


本文由 @白羽 发布于职坐标。未经许可,禁止转载。
喜欢 | 0 不喜欢 | 0
看完这篇文章有何感觉?已经有0人表态,0%的人喜欢 快给朋友分享吧~
评论(0)
后参与评论

您输入的评论内容中包含违禁敏感词

我知道了

助您圆梦职场 匹配合适岗位
验证码手机号,获得海同独家IT培训资料
选择就业方向:
人工智能物联网
大数据开发/分析
人工智能Python
Java全栈开发
WEB前端+H5

请输入正确的手机号码

请输入正确的验证码

获取验证码

您今天的短信下发次数太多了,明天再试试吧!

提交

我们会在第一时间安排职业规划师联系您!

您也可以联系我们的职业规划师咨询:

小职老师的微信号:z_zhizuobiao
小职老师的微信号:z_zhizuobiao

版权所有 职坐标-一站式IT培训就业服务领导者 沪ICP备13042190号-4
上海海同信息科技有限公司 Copyright ©2015 www.zhizuobiao.com,All Rights Reserved.
 沪公网安备 31011502005948号    

©2015 www.zhizuobiao.com All Rights Reserved

208小时内训课程