第一节检测依赖(代码片段)

mysic mysic     2022-12-21     789

关键词:

        令人惊讶的是,这很容易。 记住单元测试的一个黄金法则:隔离。 在程序中,如果另一个函数被调用或另一个类时,则含有它的代码不被隔离。 这可能导致测试方法或功能之外的测试失败。 因此,它不能被视为单元测试。 使用诸如文件系统,数据库和网络之类的资源也是如此。 结果可能会受到这些资源的影响,从而导致代码不是孤立的,因此它不是单元测试。

        为了演示依赖在现实世界中的含义,下面的代码片段是User类的一个简单示例。 此类包装代码以创建用户,将其存储在数据库中,并发送激活电子邮件。

<?php
namespace Application;
/**
 * Class User
 * @package Application
 */
class User

    public $userId;
    public $firstName;
    public $lastName;
    public $email;
    public $password;
    public $salt;

    /**
     * @param array $options
     */
    public function __construct ( array $options )
    
        foreach ($options as $key => $value) 
            if (property_exists( $this, $key )) 
                $this->$key = $value;
            
        
    

    /**
     * validates properties
     * * @return bool
     */
    public function isInputValid ()
    
        if (empty( $this->firstName ) || empty( $this->lastName ) ||
            empty( $this->email ) || empty( $this->password ) ||
            !filter_var( $this->email, FILTER_VALIDATE_EMAIL )) 
            return false;
         else 
            return true;
        
    

    /**
     * creates password hash
     */
    public function createPassword ()
    
        $this->salt     =
            substr( str_shuffle( "0123456789abcdefghijklmnopqrstuvwxyz
ABCDEFGHIJKLMNOPQRSTUVWXYZ" ), 0, 15 ); $this->password = sha1( $this->password . $this->salt ); /** * verifies password * @param string $password * @return bool */ public function verifyPassword ( $password ) return ( $this->password === sha1( $password . $this->salt ) );

如你所见,到目前为止一切顺利。 这里没问题。 代码可以很容易地测试。 每种方法都很简单; 仅使用User类中的代码。 但是,从测试的角度来看,以下代码段更糟糕:

    /**
     * sends activation email
     */
    private function sendActivationEmail ()
    
        global $config;
        $email = new UtilMail( $config );
        $email->setEmailFrom( $config->email );
        $email->setEmailTo( $this->email );
        $email->setTitle( ‘Your account has been activated‘ );
        $email->setBody( "Dear $this->firstName

    Your account has been activated

    Please visit $config->site_url

    Thank you" );
        $email->send();
    
    
    /**
     * stores user to the database
     * @return bool
     */
    public function createUser ()
    
        global $config;
        if (!$this->isInputValid()) 
            return false;
        
        $this->createPassword();
        $db = $config->db;
        /* @var $db PDO */
        $sql       = "INSERT INTO users(firstname, lastname, email,
    password, salt) VALUES (:firstname, :lastname, :email,
    :password, :salt)";
        $statement = $db->prepare( $sql );
        $statement->bindParam( ‘:firstname‘, $this->firstName );
        $statement->bindParam( ‘:lastname‘, $this->lastName );
        $statement->bindParam( ‘:email‘, $this->email );
        $statement->bindParam( ‘:password‘, $this->password );
        $statement->bindParam( ‘:salt‘, $this->salt );
        if ($statement->execute()) 
            $this->userId = $db->lastInsertId();
            $this->sendActivationEmail();
            return true;
         else 
            throw new Exception( ‘User wasn‘t saved:‘ . implode( ‘:‘, $statement->errorInfo() ) );
        
    

这是一个简单的User类,它包含或多或少的普通PHP代码,用于处理用户帐户的创建并将数据存储在数据库中。 你可以说它是简单,高效的代码; 它没有任何问题,为什么要担心呢?

首先,让我们看看代码做了什么:

  • 构造函数接受一个数组并为该对象赋予属性
  • isInputValid()函数执行基本验证
  • createPassword()函数创建salt变量,然后使用sha1()函数创建密码哈希
  • verifyPassword()函数验证提供的用户密码是否与存储在sha1()散列中的密码匹配
  • sendActivationEmail()函数发送有关新创建的帐户的通知电子邮件
  • createUser()函数将用户帐户存储到数据库中

以下是测试此类时的问题:

  • 使用全局变量$ config
  • 使用 Util Mail类,它是一个外部类,并且如预期的那样,将发送一封电子邮件
  • 使用PDO数据库连接($ config-> db)

为什么这些问题呢? 他们真的有问题吗?

通过在代码中添加依赖项,您将增加复杂性。 代码越复杂,它包含错误的可能性就越大,重构就越困难。 例如,只需将$ config设置为全局变量,就可以非常轻松地将全局变量传递给测试。 然而,问题是以简单传递的对象开始的东西通常会变得更复杂。 要设置应用程序的配置,您需要创建类加载器,错误处理程序,加载配置等等。 突然间,您必须启动应用程序并执行数百行代码; 而不是测试一个类,您正在测试一半的应用程序。 一个简单的建议是避免类中的全局变量和会话变量。

我们的示例中的另一个问题是使用Mail类。 如果要运行测试,则不希望发送电子邮件。

同样,另一个问题是与数据库的连接。 PHP已经成为一种脚本语言,它用于快速存储和检索MySQL数据库中的数据。 这种只是将数据传入和传出数据库的代码非常常见。 它有效,但考虑一下你是否想要改变行为; 例如,导入用户而没有他们的密码? 在这种情况下你能做些什么; 使用另一种方法并执行代码的副本?

公平地说,有很多方法可以做到这一点。 有时您可能会对将数据库交互留在类中感到满意,但是当您最终将所有代码放在一个巨大的类中时,这可能会成为问题。

以下可能是如何测试此代码的基本选项:

  • 重构代码并将逻辑拆分为实体和管理器
  • 使用集成测试并连接到数据库
  • 使用mocks创建一个模仿依赖代码功能的虚拟类

第一节,基本用法(代码片段)

推荐播客:我的Tensorflow学习之路http://wiki.jikexueyuan.com/project/tensorflow-zh/get_started/basic_usage.html项目代码:https://github.com/yongyehuang/Tensorflow-Tutorial一TensorFlow安装 TensorFlow是谷歌基于DistBelief进行 查看详情

u-boot代码分析--第一节(代码片段)

u-boot代码分析--第一节编者:weirdo时间:2020-5-12QQ:2651293248标题:u-boot代码分析第一节1.u-boot.lds文件?? 这里指的是顶层目录下面的u-boot.lds,这里需要注意的是这个文件是根据arch/arm/cpu/armvx/对应的u-boot.lds模板生成的,在不严格的... 查看详情

第一节——数据库(代码片段)

数据库的使用一、数据库的创建完整命令:CREATEDATABASE名称[[WITH][OWNER[=]用户名]//规定数据库属于哪个账户,默认属于创建账户 [TEMPLATE[=]模版] [ENCODING[=]字符集编码]//默认使用utf-8 [LC_COLLATE[=]排序规则] [L... 查看详情

第一周第一节(代码片段)

2018年3月19日一周第一次课:1.1学习之初1.2约定1.3认识Linux1.4安装虚拟机1.5安装centos7学习之初、约定在转行学习Linux运维之前就是“开挖掘机的”,零基础学员,对Linux了解的不是很多,有人会问那为什么要来学Linux,隔行如隔山... 查看详情

设置装订线(代码片段)

fromdocximportDocumentfromdocx.sharedimportCm文件=Document(r‘E:word练习页眉页脚.docx‘)第一节=文件.sections[0]print(第一节.gutter.cm)第一节.gutter=Cm(2)print(第一节.gutter.cm)文件.save(r‘E:word练习设置装订线.docx‘)  查看详情

第十一节harris角点检测原理(代码片段)

OpenCV可以检测图像的主要特征,然后提取这些特征、使其成为图像描述符,这类似于人的眼睛和大脑。这些图像特征可作为图像搜索的数据库。此外,人们可以利用这些关键点将图像拼接起来,组成一个更大的图像,比如将许多... 查看详情

第一节,基础知识之第一步:代数(代码片段)

先声明:theano模块的内容大都是参考来源于网上,并亲手实践复现一遍,也有部分内容是自己补充本文会列出所参考文章,如有版权问题,请联系我,我会及时删除#-*-coding:utf-8-*-"""CreatedonFriMar2313:33:202018@author:zy""" ‘‘‘x=T.d... 查看详情

第一节urlopen及urlretrieve(代码片段)

1fromurllibimportrequest2fromurllibimportrequest345#保存请求返回的数据,retrieve取回,检索数据6resp1=request.urlretrieve(‘http://www.baidu.com‘,‘baidu.httm‘)78#发送网页请求,并将请求放回的数据放入resp中9resp=request.urlopen(‘http://www.baidu.com‘)10pri... 查看详情

第一节——第一个java程序(代码片段)

第一个java程序第一步:用txt文本编辑新建txt文件,文件名为:HelloWord,格式名:.txt修改为.java编辑内容为:publicclassHelloWorld publicstaticvoidmain(String[]args) System.out.println("HelloWor 查看详情

easyclickhtmlui第一节html的介绍(代码片段)

EasyClickHtmlUI第一节html的介绍和基本结构网页效果图HTML的定义HTML的全称为:HyperTextMark-upLanguage,指的是超文本标记语言。标记:就是标签,<标签名称></标签名称>,比如:、等,标签大多数都是成对出现的。所谓超... 查看详情

第一节——grpc初体验(代码片段)

第一章——创建一个客服端与服务端启功grpc1.1、创建grpc的proto文件在工程目录下创建proto文件夹,在文件夹里面创建hello_grpc.proto文件在hello_grpc.proto文件中,第一行使用syntax="proto3";来声明使用proto3在hello_grpc.proto... 查看详情

第一节——docker的安装与卸载(代码片段)

docker的安装卸载旧的安装包,命令:sudoyumremovedocker\\docker-client\\docker-client-latest\\docker-common\\docker-latest\\docker-latest-logrotate\\docker-logrotate\\docker-engine安装需要的安装包,命令 查看详情

第一节丶上传(方便复习)(代码片段)

一丶上传案例one1.页面html1<div>2<formid="j_editForm"method="post">3<tableclass="align-center">4<tr>5<td>图片:</td>6<td>7<imgclass="j_upLoad"/>8<inputname="j_fi 查看详情

pandas第一节概览(代码片段)

Pandas是什么?Pandas是Python的核心数据分析支持库,提供快速、灵活、明确的数据结构,旨在简单直观地处理关系型、标记型数据。Pandas适用于处理以下类型的数据:   1、与SQL或Excel表类似的,含异构列的表... 查看详情

第一节——maven安装与配置(代码片段)

一、maven的安装下载地址:https://maven.apache.org/download.cgi解压文件夹,得到maven,命令:tar-xzvf二、maven的配置配置本地仓库:修改apache-maven-3.8.2/conf/settings.xml文件,添加<localRepository&g 查看详情

实战rollup第一节,入门(代码片段)

rollup是啥,咋不过多介绍,这里记录一下自己在看rollup文档和相关资料,然后手动来敲一些代码,并且以博客的形式输入,加深自己的理解本次的目标熟悉一些基本的配置,相比webpack来说,配置项还是... 查看详情

第一节:settimeout和setinterval定时器(代码片段)

 区别:   setInterval函数的用法与setTimeout完全一致,区别仅仅在于setInterval指定某个任务每隔一段时间就执行一次,也就是无限次的定时执行。取消定时器:(clearTimeout和clearInterval)   setTimeout和setInterval函数,都... 查看详情

贪心算法-第一节:贪心算法概述(代码片段)

文章目录一:贪心算法(1)概述(2)特点(3)框架二:典型贪心算法问题(1)无重叠区间①:题目描述②:解题思路③:完整代码(2)活动安排问题①:题目描述... 查看详情