[英]How can I test a function that is embedded in a method
I recently started doing python.我最近开始做 python。 The course I was on ended with an introduction to testing with doctest.我学习的课程以介绍如何使用 doctest 进行测试而结束。 I have written a program that uses Tkinter to display widgets and it works:-).我编写了一个程序,它使用 Tkinter 来显示小部件,它可以工作:-)。 I am using version 3.7.我正在使用 3.7 版。 However, testing it is another matter.但是,测试它是另一回事。 I can test simple functions and methods, but I hit difficulties when I have a function inside a method.我可以测试简单的函数和方法,但是当我在方法中有 function 时遇到了困难。 I am pasting below a stripped-down version of what I am trying to achieve.我粘贴在我想要实现的精简版本下面。 I tried first with doctest and it threw up an error: "AttributeError: 'function' object has no attribute 'c_square'".我首先尝试使用 doctest,但它抛出了一个错误:“AttributeError: 'function' object has no attribute 'c_square'”。
# counter.py
from tkinter import *
import doctest
count = 0
delay = 1000
class MyClass:
def __init__(self, master):
master.geometry("1000x500")
master.resizable(0, 0)
master.title("Display a counter")
frame1 = Frame(master)
frame1.pack()
label1 = Label(frame1, font = ('Courier', 15 , 'bold'))
label1.grid(row = 0, column = 0)
self.my_counter(label1)
label2 = Label(frame1, font = ('Courier', 15 , 'bold'))
label2.grid(row = 0, column = 1)
self.square_of_count(label2)
# 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 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_c_square(number):
"""
>>> test_c_square(2)
4
"""
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():
""" # main body commented out for test purposes.
root = Tk()
a = MyClass(root)
root.mainloop()
"""
doctest.testmod(verbose=True)
if __name__ == "__main__":
main()
I am using a separate test function, so that I can initialise my counter.我正在使用单独的测试 function,以便我可以初始化我的计数器。 Then someone suggested that I try unittest, so I wrote this:然后有人建议我尝试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()
This runs without throwing up any errors, the purpose of it is to set a value to the variable 'count' and read back the result.这运行不会引发任何错误,其目的是为变量“count”设置一个值并读回结果。 But I get the same response whatever value I test for, so I do not believe it is working right.但是无论我测试什么值,我都会得到相同的响应,所以我不相信它工作正常。 I also tried variations on a theme, but I just got error messages.我还尝试了一个主题的变体,但我只是收到错误消息。
Can someone please point out what I am doing wrong, I have looked about various forums and tutorials but have not seen this question asked before.有人可以指出我做错了什么,我查看了各种论坛和教程,但之前没有看到过这个问题。 I would appreciate an answer that is easy to follow, I am asperger / dyslexic and find it difficult to learn new material.我会很感激一个容易理解的答案,我是阿斯伯格症/阅读障碍症患者,很难学习新材料。 A correction with explanation would be most helpful.带有解释的更正将是最有帮助的。 Thank you.谢谢你。
First of all, avoid this kind of nesting the functions.首先,避免这种嵌套函数。 In your particular case I would highly suggest refactoring of a code in manner of creating some help private methods which you will call from the main ones, or even create whole new utility class:在您的特定情况下,我强烈建议重构代码以创建一些您将从主要方法调用的帮助私有方法,甚至创建全新的实用程序 class:
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))
In case you dont want to change your code (for some reason), there is extremely dirty way to access your inner function.如果您不想更改代码(出于某种原因),访问您的内部 function 的方式非常肮脏。 Again, a bit stupidly modified example made from your code:同样,从您的代码中修改了一个有点愚蠢的示例:
#!/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)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.