繁体   English   中英

如何计算通过unittest调用内部类方法的次数?

[英]How to count how many times a internal class method has been called through unittest?

有一种情况,我想检查内部类方法被调用了多少次。 我有一个敏感的云任务,必须根据某些情况进行计数。 我想用单元测试来增强我的应用程序,以断言特定函数被调用的次数。

要在更简单的场景中这样做,我想在以下脚本中进行测试:

class HMT:

    def __init__(self):
        self.buildedList = []

    def handle(self, string_to_explode: str):
        for exploded_part in string_to_explode.split(","):
            self.doCoolThings(exploded_part)

    def doCoolThings(self, fetched_raw_string: str):
        self.buildedList.append("Cool thing done: " + fetched_raw_string)

根据我传递给handle函数的字符串, doCoolThings将被调用 N 次(在这个简单的情况下,仅取决于字符串内的逗号数量)。

我可以通过计算builderList中结果元素的数量来进行测试:

import unittest
from HMT import HMT

class test_HMT(unittest.TestCase):

    def setUp(self):
        self.hmt = HMT()

    def test_hmt_3(self):
        string_to_test = "alpha,beta,gamma"
        self.hmt.handle(string_to_test)
        self.assertEqual(3, len(self.hmt.buildedList))

    def test_hmt_2(self):
        string_to_test = "delta,epsilon"
        self.hmt.handle(string_to_test)
        self.assertEqual(2, len(self.hmt.buildedList))

但是在实际场景中,不会有一个可用的公共类列表来始终将其元素数量与调用函数doCoolThings的次数相doCoolThings

那么,如何在不需要检查列表元素计数的情况下检查doCoolThings被调用了多少次?

我知道我可以在每次调用doCoolThings增加的类中放置一个计数器,并将其暴露在外部以供以后检查。 但我不想把与我的业务规则没有直接关系的代码弄乱。

在@jarmod 评论之后,我进入了这个代码的版本:

def mydecorator(func):
    def wrapped(*args, **kwargs):
        wrapped.calls += 1
        return func(*args, **kwargs)
    wrapped.calls = 0
    return wrapped

class HMT:

    def __init__(self):
        self.buildedList = []

    def handle(self, string_to_explode: str):
        for exploded_part in string_to_explode.split(","):
            self.doCoolThings(exploded_part)

    @mydecorator
    def doCoolThings(self, fetched_raw_string: str, *args, **kwargs):
        self.buildedList.append("Cool thing done: " + fetched_raw_string)

和测试:

import unittest
from HMT import HMT

class test_HMT(unittest.TestCase):

    def test_hmt_3_dec(self):
        hmt = HMT()
        string_to_test = "epsilon,ota,eta"
        hmt.handle(string_to_test)
        self.assertEqual(3, hmt.doCoolThings.calls)

    def test_hmt_3(self):
        hmt = HMT()
        string_to_test = "alpha,beta,gamma"
        hmt.handle(string_to_test)
        self.assertEqual(3, len(hmt.buildedList))

但仍然不能正常工作。 当我运行测试时,我收到:

.F
======================================================================
FAIL: test_hmt_3_dec (myTest.test_HMT)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "D:\Users\danil\tmp\myDec\myTest.py", line 10, in test_hmt_3_dec
    self.assertEqual(3, hmt.doCoolThings.calls)
AssertionError: 3 != 6

----------------------------------------------------------------------
Ran 2 tests in 0.001s

FAILED (failures=1)

更多的测试表明测试运行了两次,但计数器在新的实例化中也没有重置。

无论如何,最初的想法是在内部类方法中动态地放置一个观察者,并在每次触发这些方法时从外部获取(仍然,这似乎不是使用装饰器解决的问题)。

非常感谢您的回答(如果有人知道如何重置装饰器中的计数器,我也会很感激)。

from HMT import HMT


count = 0
def counter(f):
    def wrap(*args, **kwargs):
        global count
        count += 1
        return f(*args, **kwargs)
    return wrap


class test_HMT(unittest.TestCase):

    def setUp(self):
        self.hmt = HMT()
        
        # Add decorator.
        self.hmt_no_decorator = self.hmt.doCoolThings
        self.hmt.doCoolThings = counter(self.hmt.doCoolThings)
        
    def test_doCoolThings_count(self):
        repeat = 3               
        [self.hmt.doCoolThings() for _ in range(repeat)]

        self.assertEqual(counter, repeat)

    def tearDown(self):
        # Remove decorator.
        self.hmt.doCoolThings = self.hmt_no_decorator

        ...
  • 业务代码中没有修改doCoolThings 您只需获得用于测试的计数行为即可。
  • 您可以通过用对象替换计数变量来摆脱全局变量.. 或者通过做其他任何事情。 但它在测试中重要吗?

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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