• 4
  • 4
分享

引言

在软件测试中,一个项目的自动化测试包括UI自动化、API自动化、压力自动化等,把这些不同类型的自动化测试组装在一起变构成了一个项目的自动化测试。通过执行项目的自动化测试变能执行他的所有类型的自动化测试。当然,在生活中也有类似的,比如电脑,由CPU、磁盘、显卡等部分组成,一辆车由轮胎、车体、发动机等部件构成,客户在买车的时候并不知道该车是如何组装的,他只需要会开这辆车就行了。在设计模式中,我们将类似的复杂对象的各个部分按照一定的算法组合在一起,这种对象的创建工作便称为建造者模式。

简介

定义

建造者模式(Builder Pattern)使用多个简单的对象一步一步构建成一个复杂的对象,将复杂的构建与其表示相分离,使得同样的构建过程可以创建不同的表示。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。

主要解决的问题

在软件系统中,有时候面临一个"复杂对象"的创建工作,其通常由各个部分的子对象用一定算法构成;由于需求的变化,这个复杂对象的各个部分经常面临着剧烈的变化,但是将它们组合到一起的算法却相对稳定。如何应对这种变化?如何提供一种“封装机制”来隔离出“复杂对象的各个部分”的变化,从而保持系统中的“稳定构建算法”不随着需求改变而改变?
将一个复杂对象的构建与其表示相分离,使得同样的构建过程可以创建不同的表示。 变与不变分离开。

结构图

1359074-20201112155231781-1210976370.png

主要角色

  • 抽象建造者角色(Builder):为创建一个Product对象的各个部件指定抽象接口,以规范产品对象的各个组成成分的建造。一般而言,此角色规定要实现复杂对象的哪些部分的创建,并不涉及具体的对象部件的创建。

  • 具体建造者(ConcreteBuilder)

    • 实现Builder的接口以构造和装配该产品的各个部件。即实现抽象建造者角色Builder的方法。

    • 定义并明确它所创建的表示,即针对不同的商业逻辑,具体化复杂对象的各部分的创建。

    • 提供一个检索产品的接口。

    • 构造一个使用Builder接口的对象即在指导者的调用下创建产品实例。

  • 指导者(Director):调用具体建造者角色以创建产品对象的各个部分。指导者并没有涉及具体产品类的信息,真正拥有具体产品的信息是具体建造者对象。它只负责保证对象各部分完整创建或按某种顺序创建。

  • 产品角色(Product):建造中的复杂对象。它要包含那些定义组件的类,包括将这些组件装配成产品的接口。

具体实现

以一个项目的自动化测试由UI自动化、API自动化、压力自动化组成为例。

产品角色。自动化测试类。

public sealed class AuToTest
    {

        // 测试用例收集
        private IList<string> allCases = new List<string>();
        
        // 将所有的测试用例集中在一起
        public void addCases(string testcases)
        {
            allCases.Add(testcases);
        }
        
        // 进行测试
        public void Test()
        {
            Console.WriteLine("============ 开始执行测试用例 ============");
            foreach (string cases in allCases)
            {
                Console.WriteLine(cases + "执行完毕!");
            }
            Console.WriteLine("============ 执行测试用例结束 ============");
        }
    }

抽象建造者:包含创建产品各个子部件的抽象方法。自动化测试类。

public abstract class Builder
    {

        // 创建UI自动化测试用例
        public abstract void BuildCasesUI();

        // 创建接口自动化测试用例
        public abstract void BuildCasesAPI();

        // 创建性能自动化测试
        public abstract void BuildCasesStress();

        // 获得组装好的
        public abstract AuToTest GetAuToTest();
    }

具体建造者:实现了抽象建造者接口。以百度自动化测试和华为自动化测试为例。

public class BaiduBuidler : Builder
    {
        AuToTest BaiduAutoTest = new AuToTest();
        public override void BuildCasesUI()
        {
            BaiduAutoTest.addCases("百度 UI 自动化测试");
        }

        public override void BuildCasesAPI()
        {
            BaiduAutoTest.addCases("百度 API 自动化测试");
        }

        public override void BuildCasesStress()
        {
            BaiduAutoTest.addCases("百度 Stress 自动化测试");
        }

        public override AuToTest GetAuToTest()
        {
            return BaiduAutoTest;
        }
    }


    /// 具体创建者,比如华为
    public class HuaWeiBuidler : Builder
    {
        AuToTest HuaWeiAutoTest = new AuToTest();
        public override void BuildCasesUI()
        {
            HuaWeiAutoTest.addCases("华为 UI 自动化测试");
        }

        public override void BuildCasesAPI()
        {
            HuaWeiAutoTest.addCases("华为 API 自动化测试");
        }

        public override void BuildCasesStress()
        {
            HuaWeiAutoTest.addCases("华为 Stress 自动化测试");
        }

        public override AuToTest GetAuToTest()
        {
            return HuaWeiAutoTest;
        }
    }

指挥者:调用建造者中的方法完成复杂对象的创建。将UI自动化、API自动化、压力自动化组建成项目自动化测试。

public class Director
    {
        // 所有自动化测试组装成一个项目的自动化
        public void Construct(Builder builder)
        {
            builder.BuildCasesUI();
            builder.BuildCasesAPI();
            builder.BuildCasesStress();
        }
    }

客户类。

class Customer
    {
        static void Main(string[] args)
        {
            Director director = new Director();
            Builder baiduBuilder = new BaiduBuidler();
            Builder huaweiBuidler = new HuaWeiBuidler();

            // 百度项目进行组装
            director.Construct(baiduBuilder);
            // 组装完成后进行执行项目的自动化测试
            AuToTest baiduAutoTest = baiduBuilder.GetAuToTest();
            baiduAutoTest.Test();


            // 华为项目进行自动化测试
            director.Construct(huaweiBuidler);
            AuToTest huaweiAutoTest = huaweiBuidler.GetAuToTest();
            huaweiAutoTest.Test();
        }
    }

完整代码

using System;
using System.Collections.Generic;

namespace 建造者模式
{
    /// <summary>
    /// 客户端
    /// </summary>
    class Customer
    {
        static void Main(string[] args)
        {
            Director director = new Director();
            Builder baiduBuilder = new BaiduBuidler();
            Builder huaweiBuidler = new HuaWeiBuidler();

            // 百度项目进行组装
            director.Construct(baiduBuilder);
            // 组装完成后进行执行项目的自动化测试
            AuToTest baiduAutoTest = baiduBuilder.GetAuToTest();
            baiduAutoTest.Test();


            // 华为项目进行自动化测试
            director.Construct(huaweiBuidler);
            AuToTest huaweiAutoTest = huaweiBuidler.GetAuToTest();
            huaweiAutoTest.Test();
        }
    }



    /// <summary>
    /// 建造者模式中的指挥者
    /// 不同类型的组装,Construct 方法里面的实现就是创建复杂对象固定算法的实现,是相对稳定的
    /// </summary>
    public class Director
    {
        // 所有自动化测试组装成一个项目的自动化
        public void Construct(Builder builder)
        {
            builder.BuildCasesUI();
            builder.BuildCasesAPI();
            builder.BuildCasesStress();
        }
    }

    
    /// <summary>
    /// 自动化测试类
    /// </summary>
    public sealed class AuToTest
    {

        // 测试用例收集
        private IList<string> allCases = new List<string>();
        
        // 将所有的测试用例集中在一起
        public void addCases(string testcases)
        {
            allCases.Add(testcases);
        }
        
        // 进行测试
        public void Test()
        {
            Console.WriteLine("============ 开始执行测试用例 ============");
            foreach (string cases in allCases)
            {
                Console.WriteLine(cases + "执行完毕!");
            }
            Console.WriteLine("============ 执行测试用例结束 ============");
        }
    }


    /// <summary>
    /// 抽象建造者,定义自动化测试时需要那些内容,和最后创建的结果
    /// 在这儿要和组装进行区分,这不是组装的类型
    /// </summary>
    public abstract class Builder
    {

        // 创建UI自动化测试用例
        public abstract void BuildCasesUI();

        // 创建接口自动化测试用例
        public abstract void BuildCasesAPI();

        // 创建性能自动化测试
        public abstract void BuildCasesStress();

        // 获得组装好的
        public abstract AuToTest GetAuToTest();
    }


    /// <summary>
    /// 具体创建者,就是什么项目进行自动化测试,比如百度
    /// </summary>
    public class BaiduBuidler : Builder
    {
        AuToTest BaiduAutoTest = new AuToTest();
        public override void BuildCasesUI()
        {
            BaiduAutoTest.addCases("百度 UI 自动化测试");
        }

        public override void BuildCasesAPI()
        {
            BaiduAutoTest.addCases("百度 API 自动化测试");
        }

        public override void BuildCasesStress()
        {
            BaiduAutoTest.addCases("百度 Stress 自动化测试");
        }

        public override AuToTest GetAuToTest()
        {
            return BaiduAutoTest;
        }
    }


    /// <summary>
    /// 具体创建者,就是什么项目进行自动化测试,比如华为
    /// </summary>
    public class HuaWeiBuidler : Builder
    {
        AuToTest HuaWeiAutoTest = new AuToTest();
        public override void BuildCasesUI()
        {
            HuaWeiAutoTest.addCases("华为 UI 自动化测试");
        }

        public override void BuildCasesAPI()
        {
            HuaWeiAutoTest.addCases("华为 API 自动化测试");
        }

        public override void BuildCasesStress()
        {
            HuaWeiAutoTest.addCases("华为 Stress 自动化测试");
        }

        public override AuToTest GetAuToTest()
        {
            return HuaWeiAutoTest;
        }
    }
}

执行结果

============ 开始执行测试用例 ============
百度 UI 自动化测试执行完毕!
百度 API 自动化测试执行完毕!
百度 Stress 自动化测试执行完毕!
============ 执行测试用例结束 ============
============ 开始执行测试用例 ============
华为 UI 自动化测试执行完毕!
华为 API 自动化测试执行完毕!
华为 Stress 自动化测试执行完毕!
============ 执行测试用例结束 ============

适用场景

  • 当创建复杂对象的算法应该独立于该对象的组成部分以及它们的装配方式时。

  • 相同的方法,不同的执行顺序,产生不同的事件结果时。

  • 多个部件或零件,都可以装配到一个对象中,但是产生的运行结果又不相同时。

  • 产品类非常复杂,或者产品类中的调用顺序不同产生了不同的效能。

  • 创建一些复杂的对象时,这些对象的内部组成构件间的建造顺序是稳定的,但是对象的内部组成构件面临着复杂的变化。

优缺点

优点:

  • 封装性好,构建和表示分离。

  • 扩展性好,各个具体的建造者相互独立,有利于系统的解耦。

  • 客户端不必知道产品内部组成的细节,建造者可以对创建过程逐步细化,而不对其它模块产生任何影响,便于控制细节风险。

缺点:

  • 产品的组成部分必须相同,这限制了其使用范围。

  • 如果产品的内部变化复杂,如果产品内部发生变化,则建造者也要同步修改,后期维护成本较大。

  • 与工厂模式区别

  • 建造者模式更加注重方法的调用顺序,工厂模式注重创建对象。

  • 创建对象的力度不同,建造者模式创建复杂的对象,由各种复杂的部件组成,工厂模式创建出来的对象都一样

  • 关注重点不一样,工厂模式只需要把对象创建出来就可以了,而建造者模式不仅要创建出对象,还要知道对象由哪些部件组成。

  • 建造者模式根据建造过程中的顺序不一样,最终对象部件组成也不一样。


  • 【留下美好印记】
    赞赏支持
登录 后发表评论
+ 关注

热门文章

    最新讲堂

      • 推荐阅读
      • 换一换
          •   Windows 11 在与Android手机协同工作方面已经相当出色,但微软仍在积极探索新的方法,以便更深入地整合Android设备。Windows 11 中的"跨设备体验主机"(Cross Device Experience Host)的未来更新可能会使使用 Windows 11 的文件资源管理器查看和访问Android智能手机上的文件成为可能。  @PhantomOfEarth 在 X 上发现了在文件资源管理器中显示Android智能手机的切换按钮:  开启该功能后,Windows 11 会提示您向智能手机发送权限请求,以便操作系统访问手机上的文件:  选择&quo...
            0 0 844
            分享
          • 背景近期团队打算做一个小程序自动化测试的工具,期望能够做到业务人员操作一遍小程序后,自动还原之前的操作路径,并且捕获操作过程中发生的异常,以此来判断这次发布是否会影响小程序的基础功能。上述描述看似简单,但是中间还是有些难点的,第一个难点就是如何在业务人员操作小程序的时候记录操作路径,第二个难点就是如何将记录的操作路径进行还原。自动化 SDK如何将操作路径还原这个问题,首选官方提供的 SDK: miniprogram-automator。小程序自动化 SDK 为开发者提供了一套通过外部脚本操控小程序的方案,从而实现小程序自动化测试的目的。通过该 SDK,你可以做到以下事情:控制小程序跳转到指定页...
            0 0 3770
            分享
          • 读者提问:什么是黑盒测试,测试方法有哪些 ?阿常回答:一、黑盒测试黑盒测试不关心软件内部结构和具体实现。我们可以把软件当成一个黑盒子,通过对黑盒子进行数据输入和相关操作,观察程序的运行结果,对比实际结果和预期结果是否一致。黑盒测试包括功能测试、非功能测试。功能测试按不同阶段可划分为:单元测试、集成测试、系统测试、验收测试、回归测试。非功能测试包括:性能测试、压力测试、负载测试、安全测试、兼容性测试、易用性测试。二、测试方法黑盒测试方法包括:等价类划分法、边界值分析法、错误推测法、因果图法、判定表驱动法、正交实验设计法、功能图法、场景法等。(具体细节不展开了,网上一搜一大把)阿常碎碎念...
            0 1 1232
            分享
          •   在谈到软件测试工程师时,许多人还是会想到那些重复使用软件并试图在频繁的操作中发现 BUG的人,也就是人们常说的按照测试规范和测试案例来测试软件,检查软件是否有错误,判断软件是否稳定。但这是一个很老派和错误的观点。  由于以上观念,导致软测试工程师在最初的十年中基本上处于较低的地位,认为测试工程师从事的是技术含量不高、随时可以取代的重复工作。  据调查,国内的软件测试,在互联网刚刚兴起的十多年间被冷眼对待,特别是那些没有配备软件测试人员的中小型软件企业,测试工作往往由开发岗位兼任,通常只进行简单的白盒测试,这种做法在一定程度上等于让用户也充当了测试的角色,造成的后果往往是用户发现一堆问题后进...
            0 0 1366
            分享
          • 网络(一)简单描述下TCP协议TCP:传输控制协议,是传输层通信协议。它有面向连接、可靠、字节流传输等特点。TCP建立连接时,需要三次握手协议,TCP三次握手的过程如下:客户端发送SYN报文给服务端,进入SYN_SEND(SEQ=X)状态;服务端收到SYN报文,回应一个SYN(SEQ=Y) AC(ACK=X+1)报文,进入SYN_RECV状态;客户端收到服务端的SYN报文,回应一个ACK(ACK=Y+1)报文,开始建立连接。TCP/IP作用是什么?TCP/IP协议是一套网络通信标准,让全世界的各种不同的设备之间可以进行通信。TCP与UDP的区别?TCP传输控制协议 。UDP用户数据报协议;TC...
            14 19 3793
            分享
      • 51testing软件测试圈微信