【问题标题】:Test a function with 3 if by unit test如果通过单元测试,用 3 测试一个函数
【发布时间】:2018-01-15 16:44:58
【问题描述】:

我构建了一个简单的函数来控制密码是否有:

我构建了一个简单的函数来检查密码是否包含:

  1. 至少一个大写字母,
  2. 一个数字,
  3. 长度必须至少为 8 个字符

函数是:

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

这个函数保存在一个名为 password.py 的文件中

现在我想做一个控制每个条件的单元测试:

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()

但我不知道怎么做。如何为每个 if 设置控件?

【问题讨论】:

  • 如果密码没问题,为什么不让函数返回True?
  • validate 似乎没有理由成为类的方法而不是简单的函数。

标签: python unit-testing passwords pycharm


【解决方案1】:

首先,validate 可以只是一个返回 TrueFalse 的裸函数。

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

现在测试很简单:

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"))

您将使用各种无效密码定义单独的测试来触发您的每个条件。 (一个密码太短,另一个没有数字,等等)

在验证之前实际输入密码的任务不属于validate;它应该是一个单独的循环,使用 validate:

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

【讨论】:

    【解决方案2】:

    您不能直接对每个if 语句设置控制。您必须在测试函数中为valid.validate() 提供正确的值,以强制它进入正确的if

    【讨论】:

      【解决方案3】:

      如果你想正确地测试你的函数,你可以让它为每种情况返回一个单独的值:

      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"
      

      然后,您可以通过提供一个会违反这些规则之一的密码来检查这些分支。例如:abcdefgabcdefgh4bcdefgh4Bcdefgh

      然后让另一个方法使用该函数并使其也具有合理的返回值。

      (附注:如果您先编写测试,则不会遇到此类问题,因为您已经以易于测试的方式设计代码)

      【讨论】:

        【解决方案4】:

        你的做法很奇怪,我猜你更喜欢Java编程语言:

        1. 在 Python 中,编写函数不需要类。
        2. 您的函数不需要打印一些东西,这是调用者的问题。它返回一些东西就足够了(TrueFalse 在你的情况下)。
        3. 直接与 None 比较不是 Python 的方式。
        4. while True:break 在这种情况下毫无意义。
        5. 如果您使用returnelif 将毫无用处。

        所以重写 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
        

        现在,因为您的 UnitTest 可能位于测试代码之外的另一个模块中(因为 PyCharm 以这种方式为您创建它),您首先必须 import password - 因为您的测试函数位于 password.py 文件中。

        在 UnitTest 中,您必须定义一个测试类(就像您所做的那样)和测试方法(就像您所做的那样)。您可以在一个测试方法中定义任意数量的测试,但更好的是为每个测试定义不同的测试方法。

        测试本身(在您的测试方法中)现在 - 在重构您的原始代码之后 - 非常简单:我们将只测试返回值 TrueFalse。一个例子:

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-02-09
          • 2017-08-15
          • 2013-01-02
          • 1970-01-01
          • 1970-01-01
          • 2017-01-18
          相关资源
          最近更新 更多