Python 如何测试嵌入在方法中的函数

Python 如何测试嵌入在方法中的函数,python,tkinter,methods,doctest,Python,Tkinter,Methods,Doctest,我最近开始做python。我上的课程以介绍如何使用doctest进行测试而结束。我已经编写了一个程序,使用Tkinter来显示小部件,它可以工作:-)。我使用的是3.7版。然而,测试它是另一回事。我可以测试简单的函数和方法,但当我在方法中有一个函数时,我遇到了困难。我在下面粘贴了一个精简版的我想要实现的东西。我首先尝试了doctest,但它抛出了一个错误: “AttributeError:'函数'对象没有属性'c_square'” 我使用一个单独的测试函数,这样我就可以初始化我的计数器。 后来有

我最近开始做python。我上的课程以介绍如何使用doctest进行测试而结束。我已经编写了一个程序,使用Tkinter来显示小部件,它可以工作:-)。我使用的是3.7版。然而,测试它是另一回事。我可以测试简单的函数和方法,但当我在方法中有一个函数时,我遇到了困难。我在下面粘贴了一个精简版的我想要实现的东西。我首先尝试了doctest,但它抛出了一个错误: “AttributeError:'函数'对象没有属性'c_square'”

我使用一个单独的测试函数,这样我就可以初始化我的计数器。 后来有人建议我尝试unittest,所以我写了这样一篇文章:

import unittest
import counter

class TestCounter(unittest.TestCase):
    counter.count = 2
    print("count = ", counter.count)
    def square_of_count(self):
        result = counter.c_square()
        self.assertEqual(result, 4)
        result = counter.c_square()
        self.assertNotEqual(result, 3)


if __name__ == '__main__':
    unittest.main()
它运行时不会抛出任何错误,其目的是为变量“count”设置一个值并读回结果。但是无论我测试的是什么值,我都会得到相同的响应,所以我不相信它是正确的。我还尝试了一个主题的变体,但我只收到了错误消息

有人能指出我做错了什么吗?我看过各种论坛和教程,但以前没有看到过这个问题。
我希望你能给我一个简单易懂的答案,我患有阿斯伯格症/诵读困难症,并且发现学习新材料很困难。更正和解释将是最有帮助的。谢谢。

首先,避免这种函数嵌套。在您的特殊情况下,我强烈建议重构代码,创建一些帮助私有方法,您将从主要方法调用这些方法,甚至创建整个新的实用程序类:

class Util:
    def _init_(self):
        self.name = "Utility"
    def add_two_numbers(self, first, second):
        if(isinstance(first, int) and isinstance(second, int)):
            return first+second


class SomeFancyClass:
    def __init__(self):
        self.util = Util()
        self.constant = 4


    # This method recursively increments a counter and displays the count.
    def my_fancy_math(self, first, second):
        return self.constant * self.util.add_two_numbers(first, second)


FancyVar = SomeFancyClass()
print(FancyVar.my_fancy_math(5, 6))
如果您不想更改代码(出于某种原因),那么有一种非常肮脏的方式来访问您的内部函数。同样,从您的代码中生成了一个有点愚蠢的修改示例:

#!/usr/bin/python
# -*- coding: utf-8 -*-
# counter.py

from tkinter import *
import doctest
import types

count = 0
delay = 1000


class MyClass:

    def __init__(self, smth1):
        self.something = smth1

    # This method recursively increments a counter and displays the count.

    def my_counter(self, lbl):

        def increment_count():
            global count
            global delay
            count += 1
            string = str(count)
            lbl.config(text=string)
            lbl.after(delay, increment_count)

        increment_count()

    # This method takes the square of the counter and displays the result.

    def square_of_count(self, lbl):

        def test_function1(self, first, second):
            return first+second

        def c_square():
            global count
            squ = count * count
            string = str(squ)
            lbl.config(text=string)
            lbl.after(delay, c_square)
            return squ

        c_square()

        def test_function(self, st1):
            print(st1)

    def test_c_square(number):
        global count
        count = number
        master = Tk()
        frame1 = Frame(master)
        label = Label(frame1, font=('Courier', 15, 'bold'))
        return MyClass.square_of_count.c_square(MyClass.square_of_count.c_square)

    def main():
        doctest.testmod(verbose=True)

    if __name__ == '__main__':

        # main()

        print('done')


test_function = types.FunctionType(MyClass.square_of_count.__code__.co_consts[1],
                       {}, None, (), ())
obj = MyClass("Hi")
sum1 = test_function("", 1, 2)
print(sum1)

我正在努力理解这段代码,请给我一些解释/意见,因为我的经验还很初级,而且这篇材料远远超出了我所学的课程;值得注意的是,这一行“test_function=types.FunctionType(MyClass.square_of_count.u code_u.co_consts[1],{},None,(),())”是的,这一行在该示例中是最脏的代码,我再说一遍,根本不推荐(重构是更好的解决方案)。我将逐字解释语句:MyClass-包含方法的类的名称,square_of_count-包含要测试的内部方法的方法的名称,\uuuuuuuuu代码\uuuuuuuu_uuu-包含编译函数字节码的代码对象,co_uconsts-是函数体中出现的任何文本的元组。所以我们基本上是从字节码中“捕获”你的函数。
#!/usr/bin/python
# -*- coding: utf-8 -*-
# counter.py

from tkinter import *
import doctest
import types

count = 0
delay = 1000


class MyClass:

    def __init__(self, smth1):
        self.something = smth1

    # This method recursively increments a counter and displays the count.

    def my_counter(self, lbl):

        def increment_count():
            global count
            global delay
            count += 1
            string = str(count)
            lbl.config(text=string)
            lbl.after(delay, increment_count)

        increment_count()

    # This method takes the square of the counter and displays the result.

    def square_of_count(self, lbl):

        def test_function1(self, first, second):
            return first+second

        def c_square():
            global count
            squ = count * count
            string = str(squ)
            lbl.config(text=string)
            lbl.after(delay, c_square)
            return squ

        c_square()

        def test_function(self, st1):
            print(st1)

    def test_c_square(number):
        global count
        count = number
        master = Tk()
        frame1 = Frame(master)
        label = Label(frame1, font=('Courier', 15, 'bold'))
        return MyClass.square_of_count.c_square(MyClass.square_of_count.c_square)

    def main():
        doctest.testmod(verbose=True)

    if __name__ == '__main__':

        # main()

        print('done')


test_function = types.FunctionType(MyClass.square_of_count.__code__.co_consts[1],
                       {}, None, (), ())
obj = MyClass("Hi")
sum1 = test_function("", 1, 2)
print(sum1)