详解Python中的自定义密码验证

目录
  • 在测试:nut_and_bolt:️之前
  • 试验contains_character
    • TestContainsCharacter字符
  • 试验is_valid_size
    • TestIsValidSize
  • 试验is_valid_password
    • TestIsValidPassword
    • 重构is_valid_password
  • 结论

这些帖子将分为三个部分。

1.密码验证功能

2.重构密码验证函数

3.对密码验证功能进行单元测试

这是Python系列中自定义密码验证的第三部分,也是最后一部分。我们将看看对密码验证功能进行单元测试 .

下面是重构后的代码:

from string import (
    ascii_lowercase, ascii_uppercase,
    digits, punctuation, whitespace)

def contains_character(password: str = "", sack: str = "") -> bool:
    has_char = False
    for char in password:
        if char in sack:
            has_char = True
            break
    return has_char

def is_valid_size(password: str = "") -> bool:
    MIN_SIZE = 6
    MAX_SIZE = 20
    password_size = len(password)

    return MIN_SIZE <= password_size <= MAX_SIZE

def get_invalid_chars():
    valid_chars = {'-', '_', '.', '!', '@', '#', '$', '^', '&', '(', ')'}
    invalid_chars = set(punctuation + whitespace) - valid_chars

    return "".join(invalid_chars)

def is_valid_password(password: str = "") -> bool:
    try:
        if not password:
            return False

        new_password = password.strip()

        if not is_valid_size(new_password):
            return False

        invalid_chars = get_invalid_chars()

        if contains_character(new_password, invalid_chars):
            return False

        if not contains_character(new_password, digits):
            return False

        if not contains_character(new_password, ascii_lowercase):
            return False

        if not contains_character(new_password, ascii_uppercase):
            return False

        return True
    except:
        return False

我们的目标是为上面的代码片段编写单元测试。我们可以捕捉隐藏的错误,并在修复代码以通过测试时继续重构。

在测试:nut_and_bolt:️之前

有些事你应该知道:

  • 这将是一个单元测试
  • 我们将利用python的内置测试模块,unittest
  • 我们将测试,contains_character , is_valid_size和is_valid_password整齐
  • 测试将在test.py所以上面的片段可能在app.py(你选择你想要的名字)
  • 我们将参考

试验contains_character

contains_character返回bool,要么True或者False。所以我们可以使用assertTrue还有assertFalse方法。

我们将测试:

  • 如果既没有传递密码也没有传递sack(无参数)
  • 为了角色"i"在字符串中,"python"
  • 为了角色"py"在字符串中,"python"
  • 为了角色"python"在字符串中,"python"

有些情况下,比如int作为传递password或者当一个list作为传递sack。我们不会测试这种情况。(您应该为此进行测试)

TestContainsCharacter字符

import unittest
from app import contains_character

class TestContainsCharacter(unittest.TestCase):
    def test_empty_password_or_and_empty_sack(self):
        self.assertFalse(contains_character())

    def test_char_i_in_str_python(self):
        self.assertFalse(contains_character("i", "python"))

    def test_str_py_in_str_python(self):
        self.assertTrue(contains_character("py", "python"))

    def test_str_python_in_str_python(self):
        self.assertTrue(contains_character("python", "python"))

if __name__ == "__main__":
    unittest.main()

我们能击中ctrl + F5运行此脚本(test.py)无需调试。我们可以像下面这样运行这个脚本python3 test.py或者python3 -m unittest test.py。所有这些测试都应该通过。

试验is_valid_size

is_valid_size返回bool,要么True或者False。所以我们可以使用assertTrue还有assertFalse方法。

我们将测试:

  • 对于空密码或没有传递参数时
  • 四个字符的密码
  • 六个字符的密码
  • 十六个字符的密码
  • 二十个字符的密码
  • 21个字符的密码

TestIsValidSize

import unittest
from app import is_valid_size

class TestIsValidSize(unittest.TestCase):
    def test_empty_password(self):
        self.assertFalse(is_valid_size(""))

    def test_4_char_password(self):
        self.assertFalse(is_valid_size("pass"))

    def test_6_char_password(self):
        self.assertTrue(is_valid_size("passwd"))

    def test_16_char_password(self):
        self.assertTrue(is_valid_size("ThisIs1Password!"))

    def test_20_char_password(self):
        self.assertTrue(is_valid_size("ThisIs1Password!+20"))

    def test_21_char_password(self):
        self.assertFalse(is_valid_size("ThisIs1Password!+20&"))

if __name__ == "__main__":
    unittest.main()

所有这些测试都应该通过。

试验is_valid_password

is_valid_password返回bool,要么True或者False。所以我们可以使用assertTrue还有assertFalse方法。

我们将测试:

1.对于空密码

2.三个字符的密码

3.十个字符的密码

4.二十个字符的密码

5.对于包含无效特殊字符(如分号)的密码

6.对于没有数字的密码

7.对于没有小写字母的密码

8.对于没有大写字母的密码

9.对于没有有效特殊字符的密码

10.对于有效的密码

  • 一个尺寸以内,[6-20]
  • 至少一个小写和大写字符
  • 至少一个数字
  • 没有无效的特殊字符

TestIsValidPassword

class TestIsValidPassword(unittest.TestCase):
    def test_empty_password(self):
        self.assertFalse(is_valid_password())

    def test_password_of_size_three(self):
        self.assertFalse(is_valid_password("pas"))

    def test_password_of_size_ten(self):
        self.assertFalse(is_valid_password("Password12"))
        self.assertTrue(is_valid_password("Password1_"))

    def test_password_of_size_twenty(self):
        self.assertFalse(is_valid_password("Password12Password_$"))

    def test_password_with_invalid_special_character_semicolon(self):
        self.assertFalse(is_valid_password("Password1_;"))
        self.assertFalse(is_valid_password("Password1;"))

    def test_password_with_no_digit(self):
        self.assertFalse(is_valid_password("Password_"))

    def test_password_with_no_lowercase(self):
        self.assertFalse(is_valid_password("PASSWORD1_"))

    def test_password_with_no_uppercase(self):
        self.assertFalse(is_valid_password("password1_"))

    def test_password_without_valid_special_character(self):
        self.assertFalse(is_valid_password("Password1"))

    def test_valid_password(self):
        self.assertTrue(is_valid_password("Password1_"))
        self.assertTrue(is_valid_password("PassWord34$"))

if __name__ == "__main__":
    unittest.main()

不是所有的测试都通过了。这些测试用例不应该通过——我们期望它们不会通过。所以当我们期待False我们得到True。某处存在缺陷或错误。

这些测试没有通过:

  • test_password_of_size_ten : self.assertFalse(is_valid_password("Password12"))应该是False因为即使大小有效,它也没有特殊字符。
  • test_password_without_valid_special_character : self.assertFalse(is_valid_password("Password1"))应该是False因为没有有效的特殊字符。

这is_valid_password函数不检查是否存在有效的特殊字符。它检查无效字符,但不检查有效字符。这是由有缺陷的假设造成的,即只要密码不包含无效字符,它就包含有效字符(包括有效的特殊字符)。

重构is_valid_password

既然我们已经指出了我们的bug,我们应该做出改变并重新运行测试。

要进行的更改:

在…里get_invalid_chars,我们有set有效的特殊字符,valid_chars。让我们让它对所有函数都是全局的(例如,把它从get_invalid_chars函数并将其放在函数的顶部)。为了确保某处没有损坏,运行测试(我们预计有两种情况会失败)。请注意,即使我们移动valid_chars由于get_invalid_chars , get_invalid_chars应该还能正常工作。

这valid_chars是一个set,它可以用作中的一组get_invalid_chars . contains_character需要一段时间string sack作为论据。我们必须解析valid_chars如同string。让我们在下面创建一个函数get_invalid_chars返回一个string版本valid_chars

def get_valid_chars():
    return "".join(valid_chars)

进行测试。

让我们检查中的有效字符is_valid_password通过在return True中的语句try封锁。

if not contains_character(new_password, get_valid_chars()):
    return False

进行测试。现在,所有的测试都通过了。万岁!!:clap:️:clap:️:clap:️

这更多的是重新排列代码is_valid_password在另一种环境中自然运行良好。我们将重新排列代码is_valid_password按此顺序分别为:size, lower case, upper case, digit, invalid special character and valid special character进行测试。

结论

这is_valid_password会在app.py类似于下面的代码片段:

from string import (ascii_lowercase, ascii_uppercase, digits, punctuation,
                    whitespace)
valid_chars = {'-', '_', '.', '!', '@', '#', '$', '^', '&', '(', ')'}

def contains_character(password: str = "", sack: str = "") -> bool:
    has_char = False

    for char in password:
        if char in sack:
            has_char = True
            break

    return has_char

def is_valid_size(password: str = "") -> bool:
    MIN_SIZE = 6
    MAX_SIZE = 20
    password_size = len(password)

    return MIN_SIZE <= password_size <= MAX_SIZE

def get_invalid_chars():
    invalid_chars = set(punctuation + whitespace) - valid_chars
    return "".join(invalid_chars)

def get_valid_chars():
    return "".join(valid_chars)

def is_valid_password(password: str = "") -> bool:
    try:
        if not password:
            return False

        new_password = password.strip()

        if not is_valid_size(new_password):
            return False

        if not contains_character(new_password, ascii_lowercase):
            return False

        if not contains_character(new_password, ascii_uppercase):
            return False

        if not contains_character(new_password, digits):
            return False

        if contains_character(new_password, get_invalid_chars()):
            return False

        if not contains_character(new_password, get_valid_chars()):
            return False

        return True
    except:
        return False

单元测试将会在test.py类似于下面的代码片段:

import unittest
from app import (contains_character, is_valid_size, is_valid_password)

class TestContainsCharacter(unittest.TestCase):
    def test_empty_password_or_and_empty_sack(self):
        self.assertFalse(contains_character())

    def test_char_i_in_str_python(self):
        self.assertFalse(contains_character("i", "python"))

    def test_str_py_in_str_python(self):
        self.assertTrue(contains_character("py", "python"))

    def test_str_python_in_str_python(self):
        self.assertTrue(contains_character("python", "python"))

class TestIsValidSize(unittest.TestCase):
    def test_empty_password(self):
        self.assertFalse(is_valid_size(""))

    def test_4_char_password(self):
        self.assertFalse(is_valid_size("pass"))

    def test_6_char_password(self):
        self.assertTrue(is_valid_size("passwd"))

    def test_16_char_password(self):
        self.assertTrue(is_valid_size("ThisIs1Password!"))

    def test_20_char_password(self):
        self.assertTrue(is_valid_size("ThisIs1Password!/+20"))

    def test_21_char_password(self):
        self.assertFalse(is_valid_size("ThisIs1Password!/+20&"))

class TestIsValidPassword(unittest.TestCase):
    def test_empty_password(self):
        self.assertFalse(is_valid_password())

    def test_password_of_size_three(self):
        self.assertFalse(is_valid_password("pas"))

    def test_password_of_size_ten(self):
        self.assertFalse(is_valid_password("Password12"))
        self.assertTrue(is_valid_password("Password1_"))

    def test_password_of_size_twenty(self):
        self.assertTrue(is_valid_password("Password12Password_$"))

    def test_password_with_invalid_special_character_semicolon(self):
        self.assertFalse(is_valid_password("Password1_;"))
        self.assertFalse(is_valid_password("Password1;"))

    def test_password_with_no_digit(self):
        self.assertFalse(is_valid_password("Password_"))

    def test_password_with_no_lowercase(self):
        self.assertFalse(is_valid_password("PASSWORD1_"))

    def test_password_with_no_uppercase(self):
        self.assertFalse(is_valid_password("password1_"))

    def test_password_without_valid_special_character(self):
        self.assertFalse(is_valid_password("Password1"))

    def test_valid_password(self):
        self.assertTrue(is_valid_password("Password1_"))
        self.assertTrue(is_valid_password("PassWord34$"))

if __name__ == "__main__":
    unittest.main()

以上就是详解Python中的自定义密码验证的详细内容,更多关于Python密码验证的资料请关注我们其它相关文章!

(0)

相关推荐

  • python实现三次密码验证的示例

    需求:Python实现三次密码验证,每次验证结果需要提示,三次验证不通过需要单独提示 代码如下: user = '张无忌' password = '12345678' confirm_flag = True for i in range(0, 3): user_input = input('user:') password_input = input('password:') if user_input == user and password_input == password: print(

  • python实现密码验证合格程序的思路详解

    题目描述 输入一行或多行字符串密码,验证每行密码是否符合规范,符合提示"OK",否则"NG".密码规范为: 1.长度超过8位 2.包括大小写字母.数字.其它符号,以上四种至少三种 3.不能有相同长度超2的子串重复 解题思路 1.获取输入的多行字符串 2.对每行字符串进行密码验证: 1)如果密码长度小于等于8或者是密码中有长度超过2的重复子串,则密码NG 2)在1)不满足的情况下再看有没有至少包含大写字母.小写字母.数字.其他符号 python代码实现 import

  • 详解Python中的自定义密码验证

    目录 在测试:nut_and_bolt:️之前 试验contains_character TestContainsCharacter字符 试验is_valid_size TestIsValidSize 试验is_valid_password TestIsValidPassword 重构is_valid_password 结论 这些帖子将分为三个部分. 1.密码验证功能 2.重构密码验证函数 3.对密码验证功能进行单元测试 这是Python系列中自定义密码验证的第三部分,也是最后一部分.我们将看看

  • 详解Python中生成随机数据的示例详解

    目录 随机性有多随机 加密安全性 PRNG random 模块 数组 numpy.random 相关数据的生成 random模块与NumPy对照表 CSPRNG 尽可能随机 os.urandom() secrets 最佳保存方式 UUID 工程随机性的比较 在日常工作编程中存在着各种随机事件,同样在编程中生成随机数字的时候也是一样,随机有多随机呢?在涉及信息安全的情况下,它是最重要的问题之一.每当在 Python 中生成随机数据.字符串或数字时,最好至少大致了解这些数据是如何生成的. 用于在 P

  • 详解Python中enumerate函数的使用

    Python 的 enumerate() 函数就像是一个神秘的黑箱,你无法简单地用一句话来概括这个函数的作用与用法. enumerate() 函数属于非常有用的高级用法,而对于这一点,很多初学者甚至中级学者都没有意识到.这个函数的基本应用就是用来遍历一个集合对象,它在遍历的同时还可以得到当前元素的索引位置. 我们看一个例子: names = ["Alice","Bob","Carl"] for index,value in enumerate(n

  • 详解AngularJS中的表单验证(推荐)

    AngularJS自带了很多验证,什么必填,最大长度,最小长度...,这里记录几个有用的正则式验证 1.使用angularjs的表单验证 正则式验证 只需要配置一个正则式,很方便的完成验证,理论上所有的验证都可以用正则式完成 //javascript $scope.mobileRegx = "^1(3[0-9]|4[57]|5[0-35-9]|7[01678]|8[0-9])\\d{8}$"; $scope.emailRegx = "^[a-z]([a-z0-9]*[-_]?

  • 详解Python中pyautogui库的最全使用方法

    在使用Python做脚本的话,有两个库可以使用,一个为PyUserInput库,另一个为pyautogui库.就本人而言,我更喜欢使用pyautogui库,该库功能多,使用便利.下面给大家介绍一下pyautogui库的使用方法.在cmd命令框中输入pip3 install pyautogui即可安装该库! 常用操作 我们在pyautogui库中常常使用的方法,如下: import pyautogui pyautogui.PAUSE = 1 # 调用在执行动作后暂停的秒数,只能在执行一些pyaut

  • 详解Python中namedtuple的使用

    namedtuple是Python中存储数据类型,比较常见的数据类型还有有list和tuple数据类型.相比于list,tuple中的元素不可修改,在映射中可以当键使用. namedtuple: namedtuple类位于collections模块,有了namedtuple后通过属性访问数据能够让我们的代码更加的直观更好维护. namedtuple能够用来创建类似于元祖的数据类型,除了能够用索引来访问数据,能够迭代,还能够方便的通过属性名来访问数据. 接下来通过本文给大家分享python nam

  • 详解python中groupby函数通俗易懂

    一.groupby 能做什么? python中groupby函数主要的作用是进行数据的分组以及分组后地组内运算! 对于数据的分组和分组运算主要是指groupby函数的应用,具体函数的规则如下: df[](指输出数据的结果属性名称).groupby([df[属性],df[属性])(指分类的属性,数据的限定定语,可以有多个).mean()(对于数据的计算方式--函数名称) 举例如下: print(df["评分"].groupby([df["地区"],df["类

  • 详解python中GPU版本的opencv常用方法介绍

    引言 本篇是以python的视角介绍相关的函数还有自我使用中的一些问题,本想在这篇之前总结一下opencv编译的全过程,但遇到了太多坑,暂时不太想回看做过的笔记,所以这里主要总结python下GPU版本的opencv. 主要函数说明 threshold():二值化,但要指定设定阈值 blendLinear():两幅图片的线形混合 calcHist() createBoxFilter ():创建一个规范化的2D框过滤器 canny边缘检测 createGaussianFilter():创建一个Ga

  • 详解python中的闭包

    闭包的概念 我们尝试从概念上去理解一下闭包. 在一些语言中,在函数中可以(嵌套)定义另一个函数时,如果内部函数引用了外部函数的变量,则可能产生闭包.闭包可以用来在一个函数与一组"私有"变量之间创建关联关系.在给定函数被多次调用过程中,这些私有变量能够保持持久性. 用比较容易懂得人话说,就是当某个函数被当成对象返回时,夹带了外部变量,就形成了一个闭包.看下例子: def make_printer(msg): def printer(): print(msg) # 夹带私货(外部变量) r

  • 详解Python中第三方库Faker

    项目开发初期,为了测试方便,我们总要造不少假数据到系统中,尽量模拟真实环境. 比如要创建一批用户名,创建一段文本,电话号码,街道地址.IP地址等等. 平时我们基本是键盘一顿乱敲,随便造个什么字符串出来,当然谁也不认识谁. 现在你不要这样做了,用Faker就能满足你的一切需求. 1. 安装 pip install Faker 2. 简单使用 >>> from faker import Faker >>> fake = Faker(locale='zh_CN') >&

随机推荐