简体   繁体   中英

Test a function with 3 if by unit test

I build a simple function that control if a password have:

I built a simple function that checks if a password contains:

  1. at least one uppercase letter,
  2. a number,
  3. must be at least 8 characters long

The function is:

import re

class Password():
    def validate(password):
        while True:
            if len(password) < 8:
                print("False")
            elif re.search('[0-9]', password) is None:
                print("False")
            elif re.search('[A-Z]', password) is None:
                print("False")
            else:
                print("Your password seems fine")
                break

This function is saved in a file called password.py

Now I want do a unit test that control each condition:

import Password
import unittest

class TestPassword(unittest.TestCase):
    def test_password(self):
        valid = Password.Password()
        self.assertEqual("asdfA1qw",valid.validate())


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

But I don't know how. How can i set a control for each if?

First, validate can just be a bare function that returns True or False as appropriate.

def validate(password):
    if len(password) < 8:
        return False
    elif re.search('[0-9]', password) is None:
        return False
    elif re.search('[A-Z]', password) is None:
        return False
    else:
        return True

Now the tests are trivial:

import Password
import unittest

class TestPassword(unittest.TestCase):
    def test_password(self):
        self.assertTrue(Password.validate("asdfA1qw"))

    def test_short_password(self):
        self.assertFalse(Password.validate("foo"))

You would define separate tests with various invalid passwords to trigger each of your conditions. (One with a too-short password, another without any numbers, etc.)

The task of actually inputting a password until it validates does not belong in validate ; it should be a separate loop that uses validate :

while True:
    password = input("Enter a password: ")
    if Password.validate(password):
        break
    print("Password invalid, try again", file=sys.stderr)

You cannot directly set control on each if statement. You have to provide right value to valid.validate() in your test function to force it to go into right if .

If you want to test your function properly, you could make it return an individual value for each case:

def validate(password):
    if len(password) < 8:
        return 'password must have at least 8 characters'
    elif re.search('[0-9]', password) is None:
        return 'password must at least contain a numeric character'
    elif re.search('[A-Z]', password) is None:
        return 'password must aat least contain an upper case character'
    else:
        return "Your password seems fine"

Then you can check those branches by coming up with a password that will break one of these rules. eg: abcdefg , abcdefgh , 4bcdefgh , 4Bcdefgh

Then have another method use that function an make it have a reasonable return value, too.

(Opinionated note: If you write your test first, you don't run into such problems, since you will already design your code in a way that it is easy testable)

Your approach is very weird, I suppose that you prefer Java programming language:

  1. In Python you not need a class for writing a function.
  2. Your function need not print something, it is a matter of a caller. It is sufficient that it returns something ( True or False in your case).
  3. Direct comparing with None is not a Pythonic way.
  4. while True: and break is meaningless in this situation.
  5. elif are useless if you will use return .

So it's sufficient to rewrite is as

import re

def validate(password):
    if len(password) < 8:
        return False
    if not re.search('[0-9]', password):
        return False
    if not re.search('[A-Z]', password):
        return False
    return True

Now, because your UnitTest is probably in an another module than your tested code (because PyCharm creates it for you in that way), you first have to import password - as your tested function is in the password.py file.

In UnitTest you must define a test class (as you did), and test methods (as you did). You may define as many tests in a single test method as you wish, but much better is to define different test method for every test.

Tests themselves (in your testing methods) will be now - after refactoring your original code - very simple: We will test only for return values True or False . An example:

self.assertTrue(password.validate("asdfA1qw"))

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM