Как я могу проверить функцию, которая встроена в метод - PullRequest
0 голосов
/ 14 октября 2019

Я недавно начал заниматься питоном. Курс, на котором я был, закончился введением в тестирование с помощью doctest. Я написал программу, которая использует Tkinter для отображения виджетов, и она работает :-). Я использую версию 3.7. Однако тестирование - это другое дело. Я могу тестировать простые функции и методы, но сталкиваюсь с трудностями, когда у меня есть функция внутри метода. Я вставляю ниже урезанную версию того, чего я пытаюсь достичь. Сначала я попытался с doctest, и он выдал ошибку: «AttributeError: у объекта 'function' нет атрибута '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()

Я использую отдельную функцию тестирования, чтобы я мог инициализировать свойсчетчик. Тогда кто-то предложил мне попробовать 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' и прочитать результат обратно,Но я получаю один и тот же ответ независимо от значения, которое проверяю, поэтому я не верю, что он работает правильно. Я также пробовал вариации на тему, но только что получил сообщение об ошибке.

Может кто-нибудь указать, что я делаю неправильно, я просматривал различные форумы и учебные пособия, но не видел, чтобы этот вопрос задавался ранее. Я был бы признателен за ответ, за которым легко следовать, я аспергер / дислексик и мне трудно выучить новый материал. Исправление с объяснением было бы наиболее полезным. Спасибо.

1 Ответ

0 голосов
/ 14 октября 2019

Прежде всего, избегайте такого вложения функций. В вашем конкретном случае я бы настоятельно рекомендовал рефакторинг кода, чтобы создать некоторые частные методы справки, которые вы будете вызывать из основных, или даже создать совершенно новый класс утилит:

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