【问题标题】:Unit testing using library 'unittest' in Python 3在 Python 3 中使用库“unittest”进行单元测试
【发布时间】:2019-12-29 20:37:12
【问题描述】:

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

使用方法 init 定义一个类 Circle,该方法用 init 方法初始化一个圆 属性半径,有以下限制。

  1. 半径必须是数值,如果不引发类型错误,错误消息“半径必须是数字”。
  2. 两边的半径必须在 0 到 1000 之间,如果不引发错误消息“radius must be between 0 and 1000 包”
  3. 定义一个类方法 area 和圆周,它必须返回四舍五入到小数点后 2 位的值。

完成类TestingCircleCircumference的定义 测试圆周方法的行为,如下所述。

定义测试方法test_circlecircum_with_random_numerical_radius 它创建半径为 2.5 的圆 c1 并检查其是否计算 圆周匹配值 15.71

定义测试方法test_circlecircum_with__min_radius 创建半径为 0 的圆 c2 并检查其是否已计算 圆周匹配值 0

定义测试方法test_circlecircum_with_max_radius 创建半径为 1000 的圆 c3 并检查其是否已计算 圆周匹配值 6283.19

我的代码是:

import inspect
import re
import unittest
import math

class Circle:

    def __init__(self, radius):

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

    y = math.pi*(self.radius**2)
    return round(y, 2)

def circumference(self):

    x = math.pi*2*self.radius
    return round(x, 2)

class TestCircleArea(unittest.TestCase):

    def test_circlearea_with_random_numeric_radius(self):

        c1 = Circle(2.5)
        self.assertEqual(c1.area(), 19.63)


    def test_circlearea_with_min_radius(self):

        c2 = Circle(0)
        self.assertEqual(c2.area(), 0)

    def test_circlearea_with_max_radius(self):

        c3 = Circle(1000.1)
        self.assertEqual(c3.area(), 3141592.65)

以下代码由系统生成,我无法编辑。此代码来自HackerRank

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(TestCircleArea.test_circlearea_with_random_numeric_radius)
    doc2 = inspect.getsource(TestCircleArea.test_circlearea_with_min_radius)
    doc3 = inspect.getsource(TestCircleArea.test_circlearea_with_max_radius)

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

    print(str(assert1_count))

    assert1_count = len(re.findall(r'assertEqual', doc2))

    print(str(assert1_count))

    assert1_count = len(re.findall(r'assertEqual', doc3))

    print(str(assert1_count))

我得到的错误是:

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

【问题讨论】:

  • 这与您的问题无关,但请注意您在__init__ 中的错误处理实际上没有任何意义。为什么首先抛出错误时不包含消息,而不是捕获它们然后抛出同一类的新错误但带有消息?想象一下,您有第二个理由使用ValueError,例如您想为负数发送与大于 1,000 的数字不同的消息;您如何区分 except 块中的两者?
  • 至于你的具体问题,如果pass_count[0]IndexError,那么pass_count是空的。目前尚不清楚您为什么要为测试做如此复杂的事情,但您应该检查output.txt 中的实际内容。
  • pass_count 为空,因为它无法根据您定义的条件在您的 output.txt 中找到任何输出行。
  • output.txt 中没有以'.' 开头的行。
  • 浮点数的精确匹配应该如何在这里工作?

标签: python python-3.x unit-testing python-3.6 python-unittest


【解决方案1】:

只需修改代码如下:

  1. 移除/删除passcount行
  2. 直接分配值,即要执行的测试总数。
  3. 尽情享受吧,没有更多错误。

这只是为了跳过一直烦人的默认内容。

【讨论】:

    【解决方案2】:

    我能够使用下面的类和测试类方法解决给定的问题。

    class Circle:
        
        def __init__(self, radius):
            # Define the initialization method below
            self.radius = radius
            if not isinstance(self.radius, (int, float)):
                raise TypeError("radius must be a number")
            elif self.radius < 0 or self.radius > 1000:
                raise ValueError("radius must be between 0 and 1000 inclusive")
            else:
                pass
            
        def area(self):
            # Define the area functionality below
            return round(math.pi*(self.radius**2), 2)
                   
        def circumference(self):
            # Define the circumference functionality below
            return round(2*math.pi*self.radius, 2)
            
    class TestCircleCircumference(unittest.TestCase):
        
        def test_circlecircum_with_random_numeric_radius(self):
            # Define a circle 'c1' with radius 2.5 and check if 
            # its circumference is 15.71
            c1 = Circle(2.5)
            self.assertEqual(c1.circumference(), 15.71)
    
            
        def test_circlecircum_with_min_radius(self):
            # Define a circle 'c2' with radius 0 and check if 
            # it's circumference is 0.
            c2 = Circle(0)
            self.assertEqual(c2.circumference(),0)
                    
        def test_circlecircum_with_max_radius(self):
            # Define a circle 'c3' with radius 1000 and check if 
            # it's circumference is 6283.19.
            c3 = Circle(1000)
            self.assertEqual(c3.circumference(),6283.19)
    

    【讨论】:

      【解决方案3】:

      您收到错误是因为 c3 的值由于您在 __init__ 方法中设置的条件而未初始化。

      如果要初始化为1000.1,请去掉:

      class Circle:
          
          def __init__(self, radius):
              self.radius = radius
      
          def area(self):
              return round((math.pi*(self.radius)**2), 2)
              
                     
          def circumference(self):
              return round((math.pi*(self.radius)*2), 2)
      

      还有一件事:c3 的面积是 3142221.0,而不是你正在测试的值。请打印并检查一次。

      class TestCircleArea(unittest.TestCase):
          
          def test_circlearea_with_random_numeric_radius(self):
              c1 = Circle(2.5)
              self.assertEqual(c1.area(), 19.63)
              
          def test_circlearea_with_min_radius(self):
              c2 = Circle(0)
              self.assertEqual(c2.area(), 0.0)
      
          def test_circlearea_with_max_radius(self):
              c3 = Circle(1000.1)
              #print(c3.area())
              self.assertEqual(c3.area(), 3142221.0)
      

      【讨论】:

        【解决方案4】:
        def test_circlearea_with_max_radius(self):
            c3 = Circle(1000)
            #print(c3.area())
            self.assertEqual(c3.area(), 3141592.65)
        

        我验证这可以正常工作。数字是 1000,而不是 1000.1。输入建议似乎有问题。

        【讨论】:

        • 浮点数的精确匹配在这里如何工作?
        【解决方案5】:

        类圈子:

        def __init__(self, radius):
          
            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):
            
            return round(math.pi*(self.radius**2),2) 
                   
        def circumference(self):
         
            return round((math.pi*self.radius*2),2)
        
            
        

        类TestCircleArea(unittest.TestCase):

        def test_circlearea_with_random_numeric_radius(self):
            
            c1 = Circle(2.5)
            self.assertEqual(c1.area(), 19.63)
            
        def test_circlearea_with_min_radius(self):
            
            c2 = Circle(0)
            self.assertEqual(c2.area(), 0)
            
        def test_circlearea_with_max_radius(self):
            
            c3 = Circle(1000)
            self.assertEqual(c3.area(), 3141592.65)
        

        【讨论】:

          猜你喜欢
          • 2022-10-18
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-04-22
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多