詳解Python中的自定義密碼驗(yàn)證
這些帖子將分為三個(gè)部分。
1.密碼驗(yàn)證功能
2.重構(gòu)密碼驗(yàn)證函數(shù)
3.對(duì)密碼驗(yàn)證功能進(jìn)行單元測(cè)試
這是Python系列中自定義密碼驗(yàn)證的第三部分,也是最后一部分。我們將看看對(duì)密碼驗(yàn)證功能進(jìn)行單元測(cè)試 .
下面是重構(gòu)后的代碼:
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我們的目標(biāo)是為上面的代碼片段編寫單元測(cè)試。我們可以捕捉隱藏的錯(cuò)誤,并在修復(fù)代碼以通過(guò)測(cè)試時(shí)繼續(xù)重構(gòu)。
在測(cè)試:nut_and_bolt:?之前
有些事你應(yīng)該知道:
- 這將是一個(gè)單元測(cè)試
- 我們將利用python的內(nèi)置測(cè)試模塊,unittest
- 我們將測(cè)試,contains_character , is_valid_size和is_valid_password整齊
- 測(cè)試將在test.py所以上面的片段可能在app.py(你選擇你想要的名字)
- 我們將參考
試驗(yàn)contains_character
contains_character返回bool,要么True或者False。所以我們可以使用assertTrue還有assertFalse方法。
我們將測(cè)試:
- 如果既沒有傳遞密碼也沒有傳遞sack(無(wú)參數(shù))
- 為了角色"i"在字符串中,"python"
- 為了角色"py"在字符串中,"python"
- 為了角色"python"在字符串中,"python"
有些情況下,比如int作為傳遞password或者當(dāng)一個(gè)list作為傳遞sack。我們不會(huì)測(cè)試這種情況。(您應(yīng)該為此進(jìn)行測(cè)試)
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運(yùn)行此腳本(test.py)無(wú)需調(diào)試。我們可以像下面這樣運(yùn)行這個(gè)腳本python3 test.py或者python3 -m unittest test.py。所有這些測(cè)試都應(yīng)該通過(guò)。
試驗(yàn)is_valid_size
is_valid_size返回bool,要么True或者False。所以我們可以使用assertTrue還有assertFalse方法。
我們將測(cè)試:
- 對(duì)于空密碼或沒有傳遞參數(shù)時(shí)
- 四個(gè)字符的密碼
- 六個(gè)字符的密碼
- 十六個(gè)字符的密碼
- 二十個(gè)字符的密碼
- 21個(gè)字符的密碼
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()所有這些測(cè)試都應(yīng)該通過(guò)。
試驗(yàn)is_valid_password
is_valid_password返回bool,要么True或者False。所以我們可以使用assertTrue還有assertFalse方法。
我們將測(cè)試:
1.對(duì)于空密碼
2.三個(gè)字符的密碼
3.十個(gè)字符的密碼
4.二十個(gè)字符的密碼
5.對(duì)于包含無(wú)效特殊字符(如分號(hào))的密碼
6.對(duì)于沒有數(shù)字的密碼
7.對(duì)于沒有小寫字母的密碼
8.對(duì)于沒有大寫字母的密碼
9.對(duì)于沒有有效特殊字符的密碼
10.對(duì)于有效的密碼
- 一個(gè)尺寸以內(nèi),[6-20]
- 至少一個(gè)小寫和大寫字符
- 至少一個(gè)數(shù)字
- 沒有無(wú)效的特殊字符
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()不是所有的測(cè)試都通過(guò)了。這些測(cè)試用例不應(yīng)該通過(guò)——我們期望它們不會(huì)通過(guò)。所以當(dāng)我們期待False我們得到True。某處存在缺陷或錯(cuò)誤。
這些測(cè)試沒有通過(guò):
- test_password_of_size_ten : self.assertFalse(is_valid_password("Password12"))應(yīng)該是False因?yàn)榧词勾笮∮行?,它也沒有特殊字符。
- test_password_without_valid_special_character : self.assertFalse(is_valid_password("Password1"))應(yīng)該是False因?yàn)闆]有有效的特殊字符。
這is_valid_password函數(shù)不檢查是否存在有效的特殊字符。它檢查無(wú)效字符,但不檢查有效字符。這是由有缺陷的假設(shè)造成的,即只要密碼不包含無(wú)效字符,它就包含有效字符(包括有效的特殊字符)。
重構(gòu)is_valid_password
既然我們已經(jīng)指出了我們的bug,我們應(yīng)該做出改變并重新運(yùn)行測(cè)試。
要進(jìn)行的更改:
在…里get_invalid_chars,我們有set有效的特殊字符,valid_chars。讓我們讓它對(duì)所有函數(shù)都是全局的(例如,把它從get_invalid_chars函數(shù)并將其放在函數(shù)的頂部)。為了確保某處沒有損壞,運(yùn)行測(cè)試(我們預(yù)計(jì)有兩種情況會(huì)失敗)。請(qǐng)注意,即使我們移動(dòng)valid_chars由于get_invalid_chars , get_invalid_chars應(yīng)該還能正常工作。
這valid_chars是一個(gè)set,它可以用作中的一組get_invalid_chars . contains_character需要一段時(shí)間string sack作為論據(jù)。我們必須解析valid_chars如同string。讓我們?cè)谙旅鎰?chuàng)建一個(gè)函數(shù)get_invalid_chars返回一個(gè)string版本valid_chars
def get_valid_chars():
return "".join(valid_chars)
進(jìn)行測(cè)試。
讓我們檢查中的有效字符is_valid_password通過(guò)在return True中的語(yǔ)句try封鎖。
if not contains_character(new_password, get_valid_chars()):
return False
進(jìn)行測(cè)試?,F(xiàn)在,所有的測(cè)試都通過(guò)了。萬(wàn)歲?。?clap:?:clap:?:clap:?
這更多的是重新排列代碼is_valid_password在另一種環(huán)境中自然運(yùn)行良好。我們將重新排列代碼is_valid_password按此順序分別為:size, lower case, upper case, digit, invalid special character and valid special character進(jìn)行測(cè)試。
結(jié)論
這is_valid_password會(huì)在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單元測(cè)試將會(huì)在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中的自定義密碼驗(yàn)證的詳細(xì)內(nèi)容,更多關(guān)于Python密碼驗(yàn)證的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
詳解Python如何巧妙實(shí)現(xiàn)數(shù)學(xué)階乘n!
一個(gè)正整數(shù)的階乘(factorial)是所有小于及等于該數(shù)的正整數(shù)的積,并且0的階乘為1。自然數(shù)n的階乘寫作n!,本文就給大家介紹如何使用python和第三方庫(kù)來(lái)實(shí)現(xiàn)數(shù)學(xué)運(yùn)算中的階乘以及階乘累計(jì)求和2023-03-03
python輸出100以內(nèi)的質(zhì)數(shù)與合數(shù)實(shí)例代碼
本文通過(guò)實(shí)例代碼給大家介紹了python輸出100以內(nèi)的質(zhì)數(shù)與合數(shù)的方法,非常不錯(cuò),具有一定的參考借鑒價(jià)值,需要的朋友參考下吧2018-07-07
一個(gè)Python優(yōu)雅的數(shù)據(jù)分塊方法詳解
在做需求過(guò)程中有一個(gè)對(duì)大量數(shù)據(jù)分塊處理的場(chǎng)景,具體來(lái)說(shuō)就是幾十萬(wàn)量級(jí)的數(shù)據(jù),分批處理,每次處理100個(gè)。這時(shí)就需要一個(gè)分塊功能的代碼。本文為大家分享了一個(gè)Python中優(yōu)雅的數(shù)據(jù)分塊方法,需要的可以參考一下2022-05-05
詳解Python如何實(shí)現(xiàn)Excel數(shù)據(jù)讀取和寫入
這篇文章主要為大家詳細(xì)介紹了python如何實(shí)現(xiàn)對(duì)EXCEL數(shù)據(jù)進(jìn)行讀取和寫入,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-04-04
python自動(dòng)化測(cè)試selenium核心技術(shù)處理彈框
這篇文章主要為大家介紹了python自動(dòng)化測(cè)試selenium核心技術(shù)處理彈框的示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助2021-11-11
python實(shí)現(xiàn)QQ空間自動(dòng)點(diǎn)贊功能
這篇文章主要為大家詳細(xì)介紹了python實(shí)現(xiàn)QQ空間自動(dòng)點(diǎn)贊功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-04-04
使用PyTorch實(shí)現(xiàn)去噪擴(kuò)散模型的完整代碼
在本文中,我們將深入研究DDPM的復(fù)雜性,涵蓋其訓(xùn)練過(guò)程,包括正向和逆向過(guò)程,并探索如何執(zhí)行采樣,在整個(gè)探索過(guò)程中,我們將使用PyTorch從頭開始構(gòu)建DDPM,并完成其完整的訓(xùn)練,需要的朋友可以參考下2024-01-01

