博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
构建一个ASP.NET Wiki来解释TDD
阅读量:3525 次
发布时间:2019-05-20

本文共 7741 字,大约阅读时间需要 25 分钟。

目录


TDDBDD用例子解释

介绍

在本文中,我将尝试解释什么是TDD以及它在开发过程中的帮助。有很多资源和书籍可以做到这一点,但我将尝试用一个简单的实例介绍。这比你在书中读到的严格定义更像是一个哲学概述。可能纯粹的这种方法的支持者会发现这个解释有点不完整(对不起......),但我认为这足以开始学习和理解基础知识。我的主要目的不是写另一本关于TDD的书,而只是用清晰简单的单词解释它是什么,这样初学者也可以理解和接受它。

什么是TDD

从维基百科的定义开始:

引用:

测试驱动开发TDD)是一个,它依赖于非常短的开发周期的重复:需求变成非常具体的,然后软件被改进以仅通过新的测试。这与软件开发相反,软件开发允许添加未经证明符合要求的软件。

清楚吗?TDD的主要目的是创建一种策略,其中测试将推动开发过程,以使编码更有效,更高效,减少回归的。

先决条件是以较小的步骤分解大任务并使用单元测试进行开发。这允许您处理较小的代码片段,使其工作,然后将许多工作部分集成在一起。

TDD的好处

TDD引入您的编码体验将达到一个转折点。以下是最重要的好处的简短列表:

  1. 专注于非常重要的一点:你将被要求分解问题,这将有助于关注最重要的事情。
  2. 处理更简单的任务:每次使用单个、小型的任务可简化故障排除并加快开发速度。你将不会陷入编写所有代码的情况,然后某些东西不起作用,你不知道为什么。
  3. 简化的集成:当完成多个工作功能时,将所有功能放在一起将是一件愉快而轻松的任务。在回归的情况下,您将事先知道哪部分代码是坏的。
  4. 免费测试:完成完整任务后,许多单元测试仍然存在,可以用作集成\单元测试来验证代码并避免回归。

TDD不是什么

TDD是一种很好的方法,但不是:

  • 替代测试(单元测试,验收测试,UI测试)
  • 你可以在一天内学会的东西
  • 为你编写代码的东西
  • 一个神圣的人,可以驱除代码中的bug

TDD生命周期

TDD主要由三个步骤组成:

  1. 写单元测试(RED)。
  2. 让它工作(绿色)。
  3. 重构。

在该示例中,您可以编写单元测试,使用其中的代码实现该功能,直到它工作,然后重构将这段代码放在需要的地方。

步骤1,2:使测试工作

public class StripTest{    [Fact]    public static void StripHTml()    {        string test="

test

"; string expected="test"; string result=StripHTML(test); Assert.Equal(expected,result); } public static string StripHTML(string input) { return Regex.Replace(input, "<.*?>", String.Empty); } }

3步:重构

public class StripTest{    [Fact]    public static void StripHTml()    {        string test="

test

"; string expected="test"; string result=HtmlHelper.StripHTML(test); Assert.Equal(expected,result); } }//somewhere elsepublic static class HtmlHelper{ public static string StripHTML(string input) { return Regex.Replace(input, "<.*?>", String.Empty); }}

限制

在许多情况下,很难编写涵盖实际代码使用情况的单元测试。完全逻辑的过程很容易,但是当我们要涉及数据库或UI时,编写工作的量会增加,并且在许多情况下,可能会超过好处。有一些最佳实践和框架对此有所帮助,但一般来说,并非应用程序的所有部分都可以使用普通单元测试进行测试。

什么是BDD

BDDTDD的增强,它考虑了单元测试是限制性的情况。此扩展使用开发人员作为单元测试,保持BDD的理念。您仍然可以将复杂任务分解为较小的任务,使用用户行为进行测试,和在纯后端任务中使用TDD具有相同的优势。

TDD先决条件

在团队合作中,除了了解所有涉及的技术之外,所有队友都必须了解并接受这一理念。

首先,您的代码必须由强大的单元测试系统授权:

  • .NET.NET Core:内置Visual Studioxunit(第二个是我个人的,首选的选择)
  • Javajunit运行得很好,我不需要找到另一个解决方案
  • PHPPHP单元在所有情况下都适合我

然后,重要且必须:具有允许在测试期间模拟或重新创建正确行为的体系结构。我说的是在测试期间可以在内存或本地数据库中工作的ORM,也可以使用服务或存储库模式。使用DI框架(内置在.NET Core中,autofac或其他任何......)也有帮助。

最后但并非最不重要:一个完善的构建过程,集成在一个持续的集成流程中,除了正确的配置之外,确定哪个单元测试在集成期间在其上运行是有意义的,以及在本地运行的内容。

例子

让我们尝试在现实世界的例子中实践我们对TDD的了解。我想用这种方法创建一个wiki。我的意思是一个简单的维基,用户登录,写下标记页并发布。

首先,我会将任务分解为较小的后续活动。每个子部分将使用小型单元测试开发。我将专注于wiki 页面CRUD

1步:实体到DTO映射

  1. 编写实体。
  2. 编写wiki 页面DTO
  3. 编写将实体映射到DTO的代码。
// Database entity public class WikiPageEntity{    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]    public Guid Id { get; set; }        public int Version { get; set; }    public string Slug { get; set; }    public string Body { get; set; }    public string Title { get; set; }}// DTO model in BLLnamespace WikiCore.Lib.DTO{    public  class WikiPageDTO    {        public string Title { get; set; }        public string BodyMarkDown { get; set; }        public string BodyHtml { get; set; }        public int Version { get; set; }        public string Slug { get; set; }    }}// From unit test, code omitted for brevitypublic void EntityToDTO(){    WikiPageEntity source = new WikiPageEntity()    {        Title = "title",        Slug = "titleslug",        Version =1    };    var result = Mapper.Map
(source); Assert.Equal("title", result.Title); Assert.Equal(1, result.Version);}// From Mapping configuration, code omitted for brevity public MappingProfile(){ CreateMap
().ReverseMap();}

2步:MarkdownHTML转换

  1. 创建一个转换markdownHTML 的方法:
//Before refactoring public class MarkdownTest{[Fact]public void ConvertMarkDown(){    var options = new MarkdownOptions    {        AutoHyperlink = true,        AutoNewLines = true,        LinkEmails = true,        QuoteSingleLine = true,        StrictBoldItalic = true    };    Markdown mark = new Markdown(options);    var testo = mark.Transform("#testo");    Assert.Equal("

testo

", testo);}// after refactoring ( method moved to helper[Fact]public void ConvertMarkDownHelper(){ Assert.Equal("

testo

", MarkdownHelper.ConvertToHtml("#testo"));}// From markdown helperpublic static class MarkdownHelper{ static MarkdownOptions options; static Markdown converter; static MarkdownHelper() { options = new MarkdownOptions { AutoHyperlink = true, AutoNewLines = true, LinkEmails = true, QuoteSingleLine = true, StrictBoldItalic = true }; converter = new Markdown(options); } public static string ConvertToHtml(string input) { Markdown mark = new Markdown(options); return mark.Transform(input); }}

3步:使用Markdown进行EnHance映射

  1. 更改增加HTML字段计算的映射:
// mapped profile changedpublic class MappingProfile : Profile{      public MappingProfile()    {        SlugHelper helper = new SlugHelper();        CreateMap
() .ForMember(dest => dest.BodyMarkDown, (expr) => expr.MapFrom
(x => x.Body)) .ForMember(dest => dest.BodyHtml, (expr) => expr.MapFrom
(x => MarkdownHelper.ConvertToHtml(x.Body))) .ReverseMap(); CreateMap
() .ForMember(dest => dest.Body, (expr) => expr.MapFrom
(x => x.BodyMarkDown)) .ForMember(dest => dest.Slug, (expr) => expr.MapFrom
(x => helper.GenerateSlug(x.Title))); }}// From unit test, code omitted for brevitypublic void EntityToDTO(){ WikiPageEntity source = new WikiPageEntity() { Body = "# prova h1", Title = "title", Slug = "titleslug", Version =1 }; var result = Mapper.Map
(source); Assert.Equal("title", result.Title); Assert.Equal(1, result.Version); Assert.Equal("

prova h1

", result.BodyHtml);}

4步:设置数据库迁移

  1. 运行Add-Migration脚本。
  2. 创建一个在内存中工作的单元测试来测试它。
[Fact]public void MigrateInMemory(){        var optionsBuilder = new DbContextOptionsBuilder
(); optionsBuilder.UseInMemoryDatabase(); using (var db = new DatabaseContext(optionsBuilder.Options)) { db.Database.Migrate(); } // No error assert migration was OK}

5步:实体CRUD

  1. 写一个CRUD测试。
  2. 测试一下。
[Fact]public void CrudInMemory(){    var optionsBuilder = new DbContextOptionsBuilder
(); optionsBuilder.UseInMemoryDatabase(); using (var db = new DatabaseContext(optionsBuilder.Options)) { db.Database.Migrate(); db.WikiPages.Add(new Lib.DAL.Model.WikiPageEntity() { Title = "title", Body = "#h1", Slug = "slug" }); db.SaveChanges(); var count=db.WikiPages.Where(x => x.Slug == "slug").Count(); Assert.Equal(1, count); // update, delete steps omitted for brevity }}

6步:测试服务

  1. 使用业务逻辑创建服务。
  2. 测试一下。
[Fact]public void TestSave(){    var optionsBuilder = new DbContextOptionsBuilder
(); optionsBuilder.UseInMemoryDatabase(); using (var db = new DatabaseContext(optionsBuilder.Options)) { db.Database.Migrate(); db.SaveChanges(); //this recreate same behaviour of asp.net MVC usage DatabaseWikiPageService service = new DatabaseWikiPageService(db, Mapper.Instance); service.Save(new Lib.BLL.BO.WikiPageBO() { BodyMarkDown="#h1", Title="prova prova" }); var item = service.GetPage("prova-prova"); Assert.NotNull(item); }}

7步:继续测试UI

一旦使用单元测试测试UI变得复杂,我就切换到BDD并完成了多个步骤来完成UI测试。因此,我不是编写所有代码然后测试它,而是在多个子活动中分解问题并逐个测试:

编辑

  1. 准备表单,并进行测试。
  2. 准备模型,测试从表单提交的内容填充后端模型。
  3. 集成服务以保存数据,进行测试。

视图

  1. 准备模型,传递到视图,测试它。
  2. 将模型与服务集成,以获得真实数据。测试一下。

列表

  1. 准备视图模型,将假数据传递给UI,测试它。
  2. 整合服务,测试它。

结论

TDD是一种推动测试支持的开发过程的方法。这有助于以多种方式编码,但要求所有队友都有一些基础知识。一旦完成此步骤,您将处理更简单的任务和许多可以重用的测试。如果开发时需要编写单元测试,这个过程将有助于避免回归并更快地达到目标。此外,如果您的应用程序由于复杂性而难以测试,那么您可以保持执行BDD的相同理念。

 

原文地址:

转载地址:http://yzzhj.baihongyu.com/

你可能感兴趣的文章
N2-审计方法与步骤
查看>>
N3-常见的INI配置
查看>>
代码审计 N4 常见危险函数和特殊函数(一)
查看>>
MySQL笔记
查看>>
计算机运算方法之(原码 补码 反码 移码)
查看>>
计算机组成原理之(二进制与十进制互相转换,数的定点表示与浮点数表示)例题:设浮点数字长16位,其中阶码5位(含有1位阶符),尾数11位(含有1位数符)
查看>>
冒泡排序及其优化
查看>>
选择排序(java代码实现)
查看>>
插入排序
查看>>
哈夫曼树java代码实现
查看>>
快速排序
查看>>
vue路由高亮的两种方式
查看>>
vue router 报错: Uncaught (in promise) NavigationDuplicated {_name:""NavigationDuplicated"... 的解决方法
查看>>
vue跳转页面的两种方式
查看>>
存储器题目解析(持续更新中....)
查看>>
存储器知识要点
查看>>
Cache模拟器的实现
查看>>
实验2:MIPS指令系统和MIPS体系结构
查看>>
设计模式七大原则
查看>>
手写 | spring事务
查看>>