当要测试的对象依赖另一个无法控制的对象(系统相关、第三方服务等),这个时候我们应该如何测试?

news2024/11/17 3:34:28

一.问题描述

判断文件是否有效的需求变更了:有效的文件扩展名存储在文件系统中,要测试的FileVerify类就依赖FileExtensionManager类,在这种场景下如何测试FileVerify类的逻辑呢?

1     public class FileVerify
 2     {        
 3           public bool IsValidFileName(string fileName)
 4           {
 5               FileExtensionManager manager = new FileExtensionManager();
 7               return manager.IsValid(fileName);
 8           }
 9      }
10  
11     public class FileExtensionManager
12      {
13          public bool IsValid(string fileName)
14          {
15              //从文件系统中读取文件并判断
16              return true;
17          }
18      }

二.破除依赖的3种解决方案

方法1.对被测试类继承并重写某些行为(最简单的一种方法 无需引入新的接口和实现类)该方法在简单的同时也同时失去了对被被测试代码更多的控制空间,也就时说能做的事情是有限的

修改被测试代码,将IsValid方法定义为virtual,这样子类就可以重写该方法并决定该方法返回的结果

public class FileVerify
    {
        public bool IsValidFileName(string fileName)
        {
            return IsValid(fileName);
        }

        public virtual bool IsValid(string fileName)
        {
            FileExtensionManager manager = new FileExtensionManager();
            return manager.IsValid(fileName);
        }
    }

在测试类中创建FileVerify的子类TestFileVerity并修改测试类

internal class TestFileVerify :FileVerify
    {
        public bool IsSupported { get; set; }

        public override bool IsValid(string fileName)
        {
            return IsSupported;
        }
    }

   [TestFixture]
    public class FileVerifyTests
    {
        [Test]
        public void IsValidFileName_NameSupportedExtension_RetureTrue()
        {
            TestFileVerify fileVerify = new TestFileVerify();
            fileVerify.IsSupported = true;

            bool result = fileVerify.IsValidFileName("test.txt");

            Assert.IsTrue(result);
        }
    }

注意:以下方法均需在被测试项目中定义接口IExtensionManager,并在测试项目中添加一个接口的实现类FakeExtensionManager,下面为具体代码:

public interface IExtensionManager
    {
        bool IsValid(string fileName);
    }

    public class FileExtensionManager : IExtensionManager
    {
        public bool IsValid(string fileName)
        {
            //从文件系统中读取文件并判断
            return true;
        }
    }
internal class FakeExtensionManager : IExtensionManager
    {
        public bool WillBeValid { get; set; }

        public bool IsValid(string fileName)
        {
            return WillBeValid;
        }
    }

方法2 :继承被测试类并重写方法(与方法1相比 需引入接口与测试实现类)被测试类代码修改代码如下

public class FileVerify
    {
        public bool IsValidFileName(string fileName)
        {
            return GetManager().IsValid(fileName);
        }

        public virtual IExtensionManager GetManager()
        {
            return new FileExtensionManager();
        }
    }

在测试类中创建FileVerify的子类TestFileVerity并修改测试类

internal class TestFileVerify :FileVerify
    {
        public TestFileVerify(IExtensionManager manager)
        {
            this.manager = manager;
        }

        private readonly IExtensionManager manager;

        public override IExtensionManager GetManager()
        {
            return manager;
        }
    }

    [TestFixture]
    public class FileVerifyTests
    {
        [Test]
        public void IsValidFileName_NameSupportedExtension_RetureTrue()
        {
            FakeExtensionManager manager = new FakeExtensionManager();
            manager.WillBeValid = true;
            TestFileVerify fileVerify = new TestFileVerify(manager);

            bool result = fileVerify.IsValidFileName("test.txt");

            Assert.IsTrue(result);
        }
    }

方法3:该方法的思路是被测试类依赖于接口,不依赖于具体的实现 那么问题就转换成如何给被测试类传入具体的依赖项 对于这个思路有几个解决方案

①构造函数注入

public class FileVerify
    {
        public FileVerify(IExtensionManager manager)
        {
            this.manager = manager;
        }

        private readonly IExtensionManager manager;

        public bool IsValidFileName(string fileName)
        {
            return manager.IsValid(fileName);
        }
    }

使用构造函数注入需注意:

  • 在只有一个构造函数的情况下,这个类的所有使用者都必须传入依赖
  • 当这个类还需其它的依赖,例如日志服务、Web服务,那么构造函数中会加入更多的参数,会降低可读性和可维护性;解决这种情况有两种方案:①创建一个特殊类,将创建这个类所需依赖的类型作为属性,而构造函数中只有一个参数,就是这个特殊类 ②使用第三方Ioc容器来管理依赖
      
    ②属性注入
public class FileVerify
    {
        public FileVerify()
        {
            manager = new FileExtensionManager();
        }

        public IExtensionManager Manager
        {
            get => manager;
            set => manager = value;
        }

        private IExtensionManager manager;

        public bool IsValidFileName(string fileName)
        {
            return manager.IsValid(fileName);
        }
    }

使用属性注入要比使用构造函数注入比较简单,每个测试只需要设置自己需要设置的属性

③使用工厂,从工厂类中获得实例,在被测试项目中创建工厂类的代码如下:

/// <summary>
    /// 扩展管理器工厂
    /// </summary>
    internal class ExtensionManagerFactory
    {
        private static IExtensionManager _manager;

        public static IExtensionManager Create()
        {
            if(_manager != null)
            {
                return _manager;
            }
            return new FileExtensionManager();
        }

        public static void SetManager(IExtensionManager manager)
        {
            _manager = manager;
        }
    }

被测试类代码如下:在构造函数中通过工厂类创建默认的实例

public class FileVerify
    {
        public FileVerify()
        {
            manager = ExtensionManagerFactory.Create();
        }

        private IExtensionManager manager;

        public bool IsValidFileName(string fileName)
        {
            return manager.IsValid(fileName);
        }
    }

测试代码如下:

[TestFixture]
    public class FileVerifyTests
    {
        [Test]
        public void IsValidFileName_NameSupportedExtension_RetureTrue()
        {
            FakeExtensionManager manager = new FakeExtensionManager();
            manager.WillBeValid = true;
            ExtensionManagerFactory.Create();
            FileVerify fileVerify = new FileVerify();

            bool result = fileVerify.IsValidFileName("test.txt");

            Assert.IsTrue(result);
        }
    }

方法2和方法3比方法1相对来说比较麻烦,因为引入了新的接口,新的实现,引入了工厂方法,但是这两种方法的可控制空间比较大,例如,可以在FakeExtensionManager类中模拟异常

破除依赖的3中方法就介绍完了,如有不对之处,请指出,大家共同学习!


资源分享

下面这份资源,对于想学习【软件测试】的朋友来说应该是最全面最完整的备战仓库,希望也能帮助到你!在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/83005.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

精品基于SSM的社区疫情防控平台

《基于SSM的社区疫情防控平台》该项目含有源码、论文等资料、配套开发软件、软件安装教程、项目发布教程等 使用技术&#xff1a; 开发语言&#xff1a;Java 框架&#xff1a;ssm 技术&#xff1a;JSP JDK版本&#xff1a;JDK1.8 服务器&#xff1a;tomcat7 数据库&…

(附源码)springboot螺丝加工厂订单管理 毕业设计 010346

题 目 springboot螺丝加工厂订单管理 目 录 摘要 1 1 绪论 1 1.1项目开发的背景 1 1.2项目开发的意义 1 1.3系统开发技术的特色 1 1.4论文结构与章节安排 1 2 螺丝加工厂订单管理 系统分析 3 2.1 可行性分析 3 2.2 系统流程分析 3 2.2.1数据流程 3 2.3.2业务流程 4 2.3 系统…

C++11标准模板(STL)- 算法(std::sort_heap)

定义于头文件 <algorithm> 算法库提供大量用途的函数&#xff08;例如查找、排序、计数、操作&#xff09;&#xff0c;它们在元素范围上操作。注意范围定义为 [first, last) &#xff0c;其中 last 指代要查询或修改的最后元素的后一个元素。 数据结构的堆物理结构是数…

百度地图(HTML5新特性)-全面详解(学习总结---从入门到深化)

目录 百度地图_账号和获取密钥 百度地图_初始化 百度地图_变更地图类型 百度地图_添加控件 百度地图_改变控件位置 百度地图_添加覆盖物 百度地图_自定义标注图标 百度地图_添加文本标注 百度地图_正/逆地址解析 百度地图_信息窗口 百度地图_规划驾车路线 百度地图_…

亚马逊、速卖通、阿里国际自动和手动广告的核心是什么?自己养买家号测评的好处

亚马逊等跨境电商平台在打造的新品期&#xff0c;因为选择的细分类目是非常精准刚需的&#xff0c;词少&#xff0c;所以一开始只开启了自动广告&#xff0c;自动广告跑起来&#xff0c;转化很好。 自动广告跑了一段时间之后&#xff0c;把自动广告里表现比较好的出单词都挑出…

冰雪旅游热开启!IU酒店与您畅游山水之间

连日来&#xff0c;全国多地不断调整疫情防控措施&#xff0c;提高科学精准防控能力。国家防疫“新十条”出台后&#xff0c;大众旅游热情明显增高。 据穷游网站内数据显示&#xff0c;去海南、云南等地避寒&#xff0c;或前往东北、新疆等地滑雪备受用户推崇。三亚、上海、成…

spark上传文件和追加文件到hdfs

val status uploadFile(“C:\Users\com\Desktop\测试数据\”,“/test/file/”,“报销单.docx”) if(status) println(“上传成功&#xff01;”) else println(“上传失败”) } /** 本地文件上传到 hdfs param localDirectory 本地目录 param hdfsDirectory hdfs目录 pa…

胰岛素海藻酸钠纳米粒(INS-SA-NP)|葡聚糖(Dextran)修饰Fe304纳米颗粒

胰岛素海藻酸钠纳米粒&#xff08;INS-SA-NP&#xff09;|葡聚糖(Dextran)修饰Fe304纳米颗粒 中文名称&#xff1a;胰岛素海藻酸钠纳米粒 英文名称&#xff1a;INS-SA-NP 纯度&#xff1a;95% 存储条件&#xff1a;-20C&#xff0c;避光&#xff0c;避湿 外观:固体或粘性液…

flutter系列之:如丝般顺滑的SliverAppBar

文章目录简介SliverAppBar详解SliverAppBar的使用总结简介 对于一个APP来说&#xff0c;肯定会有一个AppBar&#xff0c;这个AppBar一般包含了APP的导航信息等。虽然我们可以用一个固定的组件来做为AppBar&#xff0c;但是这样就会丢失很多特效&#xff0c;比如将AppBar固定在…

Java基础 二维数组简介

一、二维数组的定义 当一维数组元素的类型也是一维数组时&#xff0c;便构成了“数组的数组”&#xff0c;即二维数组。二维数组定义的一般格式&#xff1a; dataType arrayName[length1][length2];其中&#xff0c; dataType 为数据类型&#xff0c; arrayName 为数组名&…

TDengine3.0与2.x数据库参数对比

TDengine 已经发布很长时间了&#xff0c;产品基本稳定下来了。 以下总结了 TDengine 3.0 与 2.x 数据库参数的一些变化&#xff0c;方便大家从 2.x 切换到 3.0。 注意&#xff1a;2.x 与 3.0 文件系统不兼容&#xff0c;不能直接升级。 2.x3.xdays单位&#xff1a;天&#xff…

云原生之使用Docker部署PESMCS Ticket工单系统

云原生之使用Docker部署PESMCS Ticket工单系统一、PESMCS Ticket介绍二、检查本地系统环境1.检查系统版本2.检查docker状态三、创建mariadb容器1.创建network2.创建数据目录3.创建mariadb容器4.查看mariadb容器状态四、创建PESMCS Ticket容器1.创建PESMCS Ticket容器2.查看PESM…

【黄啊码】如何用小程序实现世界杯参赛队伍投票

本次只分享小程序端的代码实现&#xff0c;后端每个人都有自己的实现方法&#xff0c;就不写在此。 好了&#xff0c;先看实现样式&#xff1a; 本次投票实现需要一个页面和一个弹窗实现&#xff0c;我们做的是淘汰赛部分&#xff0c;在此&#xff0c;黄啊码将淘汰赛部分直接选…

配置Nginx解决http host头攻击漏洞【详细步骤】

配置Nginx解决http host头攻击漏洞【详细步骤】前言1、进入nginx目录下2、修改nginx配置文件3、添加上后重启配置文件Nginx常用基本命令仰天大笑出门去&#xff0c;我辈岂是蓬蒿人前言 大概内容&#xff1a; 安全系统渗透测试出host头攻击漏洞&#xff0c;下面是解决步骤 1、…

React组件之间的通信方式总结(上)

先来几个术语&#xff1a; 官方我的说法对应代码React elementReact元素let element<span>A爆了</span>Component组件class App extends React.Component {}无App为父元素&#xff0c;App1为子元素<App><App1></App1></App> 本文重点&…

idea中用SSH工具手动打包部署

我用的是MobaXterm工具&#xff1a; 第一步&#xff1a;先将自己的文件整体运行一下&#xff0c;确保可以正常运行 第二步&#xff1a;在Maven中找到名为XXXX&#xff08;root&#xff09;的名称展开 ---》Lifecycle &#xff0c;先点击 clean&#xff0c;确保无误后点击 pac…

clickhouse三节点三分片双副本环绕部署

文章目录clickhouse安装部署01节点 metrika.xml 配置文件信息02节点 metrika.xml 配置文件信息03节点 metrika.xml 配置文件信息macros 实例信息编辑查看结果clickhouse安装部署 rpm安装过程以及注意事项 01节点 metrika.xml 配置文件信息 <?xml version"1.0"…

笔试强训(四十三)

目录一、选择题二、编程题2.1 电话号码2.1.1 题目2.1.2 题解2.2 求和2.2.1 题目2.2.2 题解一、选择题 &#xff08;1&#xff09;下列关于synflood攻击的说法错误的是&#xff08;B&#xff09; A.服务端由于连接队列被占满而不能对外服务 B.不但能攻击TCP服务&#xff0c;还能…

做个家务,让我搞懂了 Linux I/O 模型

I/O 其实就是 input 和 output&#xff08;输入输出&#xff09; 在计算机操作系统中对应数据流的输入与输出&#xff0c;在 Linux 中&#xff0c;既有文件的 I/O&#xff0c;也有网络 I/O 无论是文件 I/O 还是网络 I/O&#xff0c;其传输过程都是类似的 今天我们以文件 I/O…

【Unity学习笔记】UnrealToUnity教程:(网上购买的素材导入Unreal+插件转Unity)

【Unity学习笔记】UnrealToUnity教程&#xff1a; 最近想从Unreal那边化点缘借借素材&#xff0c;没想到踩到一个大坑 一&#xff0c;素材导入Unreal 这个教程比较多&#xff0c;根据素材的来源&#xff0c;传送门是以下这几个&#xff1a; 1.项目之间互相迁移&#xff0c;不…