在 Python3 中使用单元测试进行单元测试

新手上路,请多包涵

我需要在 Python 中使用单元测试编写测试用例来测试圈子的创建。

  • 定义一个类 Circle 方法 __init__ 初始化一个属性为 radius 的圆,具有以下限制:

    • radius 必须是数值,如果不是引发类型错误,错误消息为“半径必须是数字”。

    • radius 两侧必须介于 0 到 1000 之间,如果不提高值错误,并显示错误消息“半径必须介于 0 到 1000 之间”

    • 定义一个类方法 areacircumference 必须返回四舍五入到两位小数的值。

完成类 TestingCircleCreation 的定义,它测试 __init__ 方法的行为,如下所述。

  • 定义 test_creating_circle_with_numerical_radius 的测试方法,它创建半径为 2.5 的圆并检查半径是否与值 2.5 匹配

  • 定义测试方法 test_creating_circle_with_negative_radius 在创建半径为 2.5 的圆时检查是否引发值错误异常并显示错误消息“半径必须介于 0 和 1000 之间”。

  • 定义测试方法 test_creating_circle_with_greaterthan_radius 检查是否 ValueError 在创建半径为 1000.1 的圆时引发异常并显示错误消息“半径必须介于 0 和 1000 之间”。

  • 定义测试方法 test_creating_circle_with_nonnumeric_radius ,它检查 TypeError 在创建半径为“hello”的圆时是否引发异常并显示错误消息“半径必须是数字”。

我在下面尝试过,但失败并出现错误

Traceback (most recent call last):
  File "..\Playground\", line 86, in <module>
    pass_count = pass_count[0]
IndexError: list index out of range

编码:

 import inspect
import re
import unittest
import math

# Define below the class 'Circle' and it's methods with proper doctests.
class Circle:
    def __init__(self, radius):
        # Define the initialization method below
        try:
            if not isinstance(radius, (int, float)):
                raise TypeError
            elif 1000 >=radius>=0:
                    self.radius=radius
            else:
                raise ValueError
        except ValueError:
            raise ValueError("radius must be between 0 and 1000 inclusive")
        except TypeError:
            raise TypeError("radius must be a number")

    def area(self):
        # Define the area functionality below
        y=math.pi*(self.radius**2)
        return round(y,2)

    def circumference(self):
        # Define the circumference functionality below
        x=math.pi*2*self.radius
        return round(x,2)

class TestCircleCreation(unittest.TestCase):
    def test_creating_circle_with_numeric_radius(self):
        # Define a circle 'c1' with radius 2.5 and check if
        # the value of c1.radius equal to 2.5 or not
        c1=Circle(2.5)
        self.assertEqual(c1.radius,2.5)

    def test_creating_circle_with_negative_radius(self):
        # Try Defining a circle 'c' with radius -2.5 and see
        # if it raises a ValueError with the message
        # "radius must be between 0 and 1000 inclusive"
        c=Circle(-2.5)
        self.assertEqual(c.radius,-2.5)
        self.assertRaises(ValueError)

    def test_creating_circle_with_greaterthan_radius(self):
        # Try Defining a circle 'c' with radius 1000.1 and see
        # if it raises a ValueError with the message
        # "radius must be between 0 and 1000 inclusive"
        c=Circle(1000.1)
        self.assertEqual(c.radius,1000.1)
        self.assertRaises(ValueError)

    def test_creating_circle_with_nonnumeric_radius(self):
        # Try Defining a circle 'c' with radius 'hello' and see
        # if it raises a TypeError with the message
        # "radius must be a number"
        c=Circle('hello')
        self.assertEqual(c.radius,'hello')
        self.assertRaises(TypeError)

if __name__ == '__main__':
    fptr = open('output.txt', 'w')

    runner = unittest.TextTestRunner(fptr)

    unittest.main(testRunner=runner, exit=False)

    fptr.close()

    with open('output.txt') as fp:
        output_lines = fp.readlines()

    pass_count = [ len(re.findall(r'\.', line)) for line in output_lines if line.startswith('.')
                     and line.endswith('.\n')]

    pass_count = pass_count[0]
    print(str(pass_count))

    doc1 = inspect.getsource(TestCircleCreation.test_creating_circle_with_numeric_radius)
    doc2 = inspect.getsource(TestCircleCreation.test_creating_circle_with_negative_radius)
    doc3 = inspect.getsource(TestCircleCreation.test_creating_circle_with_greaterthan_radius)
    doc4 = inspect.getsource(TestCircleCreation.test_creating_circle_with_nonnumeric_radius)

    assert1_count = len(re.findall(r'assertEqual', doc1))
    print(str(assert1_count))

    assert1_count = len(re.findall(r'assertEqual', doc2))
    assert2_count = len(re.findall(r'assertRaises', doc2))
    print(str(assert1_count), str(assert2_count))

    assert1_count = len(re.findall(r'assertEqual', doc3))
    assert2_count = len(re.findall(r'assertRaises', doc3))
    print(str(assert1_count), str(assert2_count))

    assert1_count = len(re.findall(r'assertEqual', doc4))
    assert2_count = len(re.findall(r'assertRaises', doc4))
    print(str(assert1_count), str(assert2_count))

原文由 R D 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 505
2 个回答

我删除了重复的 self.assertEqual(c.radius,-2.5) 断言,因为它们已经由另一个单元测试( test_creating_circle_with_numeric_radius(self) )处理,并导致你的单元测试失败。看这里例如:

     def test_creating_circle_with_negative_radius(self):
        c=Circle(-2.5)
        self.assertEqual(c.radius,-2.5) # Throwing ValueError
        self.assertRaises(ValueError)

在您的代码中, assertEquals(c.radius,-2.5) 尝试确定值 c.radius 是否等于-2.5。但是这个值没有设置,因为 -2.5 超出了可接受的范围,而是抛出了 ValueError。这可以防止检查 self.assertRaises(ValueError) 。通过从测试中删除 assertEquals 并将其保留为自己的独立测试, self.assertRaises(ValueError) 执行并允许您查看代码不符合要求的地方。

我已经更改了您的测试以使用上下文管理来捕获抛出的异常,这些异常使测试正常工作

class TestCircleCreation(unittest.TestCase):

    def test_creating_circle_with_numeric_radius(self):
        # Define a circle 'c1' with radius 2.5 and check if
        # the value of c1.radius equal to 2.5 or not
        c1 = Circle(2.5)
        self.assertEqual(c1.radius, 2.5)

    def test_creating_circle_with_negative_radius(self):
        # Try Defining a circle 'c' with radius -2.5 and see
        # if it raises a ValueError with the message
        # "radius must be between 0 and 1000 inclusive"
        with self.assertRaises(ValueError) as E:
            c = Circle(-2.5)

    def test_creating_circle_with_greaterthan_radius(self):
        # Try Defining a circle 'c' with radius 1000.1 and see
        # if it raises a ValueError with the message
        # "radius must be between 0 and 1000 inclusive"
        with self.assertRaises(ValueError) as E:
            c = Circle(1000.1)

    def test_creating_circle_with_nonnumeric_radius(self):
        # Try Defining a circle 'c' with radius 'hello' and see
        # if it raises a TypeError with the message
        # "radius must be a number"
        with self.assertRaises(TypeError) as E:
            c = Circle('hello')

虽然这也有效:

 class TestCircleCreation(unittest.TestCase):

    def test_creating_circle_with_numeric_radius(self):
        c1 = Circle(2.5)
        self.assertEqual(c1.radius, 2.5)

    def test_creating_circle_with_negative_radius(self):
        self.assertRaises(ValueError, Circle, -2.5)

    def test_creating_circle_with_greaterthan_radius(self):
        self.assertRaises(ValueError, Circle, 1000.1)

    def test_creating_circle_with_nonnumeric_radius(self):
        self.assertRaises(TypeError, Circle, 'hello')

PS:我建议您在写入文件时使用 with open ,就像您在读回文件时所做的那样。

     with open('output.txt', 'w') as fptr:
        runner = unittest.TextTestRunner(fptr)
        unittest.main(testRunner=runner, exit=False)

您的支票可以简化为

        try:
            if not isinstance(radius, (int, float)):
                raise TypeError
            elif 1000 >=radius>=0:
                    self.radius=radius
            else:
                raise ValueError
        except ValueError:
            raise ValueError("radius must be between 0 and 1000 inclusive")
        except TypeError:
            raise TypeError("radius must be a number")

至:

             if not isinstance(radius, (int, float)):
                raise TypeError("radius must be a number")

            if not 1000 >=radius>=0:
                raise ValueError("radius must be between 0 and 1000 inclusive")

            self.radius=radius

原文由 DWD 发布,翻译遵循 CC BY-SA 4.0 许可协议

class Circle:
    def __init__(self, radius):
        # Define initialization method:
        self.radius = 0
        if not isinstance(radius,(int,float)):
            raise TypeError("radius must be a number")
        elif radius < 0 or radius > 1000:
            raise ValueError("radius must be between 0 and 1000 inclusive")
        else:
            self.radius = radius

    def area(self):
        # Define area functionality:
        return round(math.pi*(self.radius**2),2)

    def circumference(self):
        # Define circumference functionality:
        return round(2*math.pi*self.radius)

class TestCircleCreation(unittest.TestCase):
    def test_creating_circle_with_numeric_radius(self):
        # Define a circle 'c1' with radius 2.5, and check if
        # the value of c1.radius is equal to 2.5 or not.
        c1 = Circle(2.5)
        self.assertEqual(c1.radius, 2.5)

    def test_creating_circle_with_negative_radius(self):
        # Define a circle 'c' with radius -2.5, and check
        # if it raises a ValueError with the message
        # "radius must be between 0 and 1000 inclusive".
        with self.assertRaises(ValueError) as e:
            c = Circle(-2.5)
        self.assertEqual(str(e.exception),"radius must be between 0 and 1000 inclusive")

    def test_creating_circle_with_greaterthan_radius(self):
        # Define a circle 'c' with radius 1000.1, and check
        # if it raises a ValueError with the message
        # "radius must be between 0 and 1000 inclusive".
        with self.assertRaises(ValueError) as e:
            c = Circle(1000.1)
        self.assertEqual(str(e.exception),"radius must be between 0 and 1000 inclusive")

    def test_creating_circle_with_nonnumeric_radius(self):
        # Define a circle 'c' with radius 'hello' and check
        # if it raises a TypeError with the message
        # "radius must be a number".
        with self.assertRaises(TypeError) as e:
            c = Circle("hello")
        self.assertEqual(str(e.exception), "radius must be a number")

原文由 Bit 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题