小编lem*_*sss的帖子

自定义unittest.mock.mock_open进行迭代

我应该如何自定义unittest.mock.mock_open来处理这段代码?

file: impexpdemo.py
def import_register(register_fn):
    with open(register_fn) as f:
        return [line for line in f]
Run Code Online (Sandbox Code Playgroud)

我第一次尝试尝试read_data.

class TestByteOrderMark1(unittest.TestCase):
    REGISTER_FN = 'test_dummy_path'
    TEST_TEXT = ['test text 1\n', 'test text 2\n']

    def test_byte_order_mark_absent(self):
        m = unittest.mock.mock_open(read_data=self.TEST_TEXT)
        with unittest.mock.patch('builtins.open', m):
            result = impexpdemo.import_register(self.REGISTER_FN)
            self.assertEqual(result, self.TEST_TEXT)
Run Code Online (Sandbox Code Playgroud)

这失败了,大概是因为代码不使用read,readline或readlines.unittest.mock.mock_open 的文档说:"read_data是要返回的文件句柄的read(),readline()和readlines()方法的字符串.对这些方法的调用将从read_data中获取数据,直到它耗尽为止这些方法的模拟非常简单.如果你需要更多地控制你要测试代码的数据,你需要自己定制这个模拟.默认情况下,read_data是一个空字符串."

由于文件没有给出暗示上会需要什么样定制我试图return_valueside_effect.都没有奏效.

class TestByteOrderMark2(unittest.TestCase):
    REGISTER_FN = 'test_dummy_path'
    TEST_TEXT = ['test text 1\n', 'test text 2\n']

    def test_byte_order_mark_absent(self):
        m = unittest.mock.mock_open()
        m().side_effect = self.TEST_TEXT
        with unittest.mock.patch('builtins.open', m):
            result = impexpdemo.import_register(self.REGISTER_FN) …
Run Code Online (Sandbox Code Playgroud)

python iteration unit-testing mocking python-mock

24
推荐指数
2
解决办法
7470
查看次数

空列表的正确类型提示是什么?

什么是正确的类型提示x = []

我的 PyCharm 编辑器中的类型检查器将此标记为错误:

labelframes: List[ttk.LabelFrame] = []
Run Code Online (Sandbox Code Playgroud)

'Optional' 不是一个选项,如:

labelframes: List[Optional[ttk.LabelFrame]] = []
Run Code Online (Sandbox Code Playgroud)

因为文档typing.Optional说明这相当于:

labelframes: List[Union[ttk.LabelFrame, None]] = []
Run Code Online (Sandbox Code Playgroud)

并且[None]不是[]

我应该提到 PyCharm 也不喜欢这样:

labelframes: List[Union[ttk.LabelFrame, None]] = [None]
Run Code Online (Sandbox Code Playgroud)

无论我尝试什么类型的提示。PyCharm 将其标记为错误,“预期在此处返回我的类型提示,但没有返回”,因此我尝试了:

labelframes: Optional[List[ttk.LabelFrame, None]] = []
Run Code Online (Sandbox Code Playgroud)

那没有用。

我知道 PEP 526 有许多遵循以下模式的示例:

x: List[str] = []
Run Code Online (Sandbox Code Playgroud)

python typing type-hinting python-3.x

12
推荐指数
2
解决办法
7592
查看次数

Tkinter的event_generate命令被忽略

我试图找出如何在对话框窗口中单元测试绑定命令.我正在尝试使用tkinter event_generate.它不像我期望的那样工作.对于这个StackOverflow问题,我通过一次调用设置了一些代码event_generate.有时这条线有效,有时就好像线条甚至不存在一样.

对话框__init__方法中的绑定如下所示:

        self.bind('<BackSpace>',  #Print "BackSpace event generated."
            lambda event: print(event.keysym, 'event generated.'))
Run Code Online (Sandbox Code Playgroud)

对话框中的任何操作都将回调其终止方法(该对话框基于Frederik Lundh在"Tkinter简介"中的对话框示例.)

    def terminate(self, event=None):
        print('terminate called')  # Make sure we got here and the next line will be called
        self.event_generate('<BackSpace>')
        self.parent.focus_set()
        self.destroy()
Run Code Online (Sandbox Code Playgroud)

使用下面的代码调用对话框时,任何用户操作都将最终调用terminate.在每种情况下"终止被叫"和"BackSpace事件生成".显示.这证明了对event_generate的调用是正确设置的.

parent = tk.Tk()
dialog = Dialog(parent)
dialog.wait_window()
Run Code Online (Sandbox Code Playgroud)

如果它是相关的,我应该提到我已经将Lundh的调用self.wait_window从他的对话框的__init__方法移动到调用者.虽然这打破了对话框的整洁封装,但似乎有必要进行自动化的单元测试.否则,unittest将显示对话框并停止等待用户输入.我不喜欢这个解决方案,但我不知道任何替代方案.

我遇到的问题是何时wait_window被直接调用terminate方法替换.这是我希望在单元测试中可以做的事情,即在不运行tkinter的mainloop或wait_window的情况下测试我的GUI代码.

parent = tk.Tk()
dialog = Dialog(parent)
dialog.terminate()
Run Code Online (Sandbox Code Playgroud)

这只打印"终止被叫"并且不打印"BackSpace事件生成".呼叫event_generate似乎没有效果.如果我在调试器中跟随调用,我可以看到event_generate()正在使用正确的参数调用tkinter .self = {Dialog} .99999999, sequence = …

python unit-testing tkinter

7
推荐指数
1
解决办法
4641
查看次数

为什么 dataclasses.astuple 返回类属性的深层副本?

在下面的代码中,该astuple函数正在执行数据类的类属性的深层复制。为什么它产生的结果与函数不同my_tuple

import copy
import dataclasses


@dataclasses.dataclass
class Demo:
    a_number: int
    a_bool: bool
    classy: 'YOhY'

    def my_tuple(self):
        return self.a_number, self.a_bool, self.classy

class YOhY:
    def __repr__(self):
        return (self.__class__.__qualname__ + f" id={id(self)}")


why = YOhY()
print(why)  # YOhY id=4369078368

demo = Demo(1, True, why)
print(demo)  # Demo(a_number=1, a_bool=True, classy=YOhY id=4369078368)

untrupled = demo.my_tuple()
print(untrupled)  # YOhY id=4369078368

trupled = dataclasses.astuple(demo)
print(trupled)  # YOhY id=4374460064

trupled2 = trupled
print(trupled2)  # YOhY id=4374460064

trupled3 = copy.copy(trupled)
print(trupled3)  # YOhY id=4374460064

trupled4 …
Run Code Online (Sandbox Code Playgroud)

python python-3.x python-dataclasses

6
推荐指数
1
解决办法
2225
查看次数

如何模拟在 isinstance 测试中使用的类?

我想测试一下功能is_myclass。请帮助我了解如何编写成功的测试。

def is_myclass(obj):
    """This absurd stub is a simplified version of the production code."""
    isinstance(obj, MyClass)
    MyClass()
Run Code Online (Sandbox Code Playgroud)

文档

unittest.mock 的 Python 文档说明了解决该isinstance问题的三种方法:

  • spec参数设置为真实的类。
  • 将真正的类分配给__class__属性。
  • spec在真实类的补丁中使用。

__class__

通常,__class__对象的属性将返回其类型。对于具有规范的模拟对象,__class__返回规范类。这允许模拟对象通过 isinstance() 测试它们正在替换/伪装为的对象:

>>> mock = Mock(spec=3)
>>> isinstance(mock, int)
True
Run Code Online (Sandbox Code Playgroud)

__class__可分配给,这允许模拟通过isinstance()检查而不强迫您使用规范:

>>> mock = Mock()
>>> mock.__class__ = dict
>>> isinstance(mock, dict)
True
Run Code Online (Sandbox Code Playgroud)

[...]

如果您使用specorspec_set并且patch()正在替换一个类,那么创建的模拟的返回值将具有相同的规范。

>>> Original = Class
>>> patcher …
Run Code Online (Sandbox Code Playgroud)

python unit-testing mocking python-unittest

5
推荐指数
1
解决办法
4057
查看次数

是否可以模拟 lambda 表达式?

前两个函数display_pane_1template_1很容易在该方法中进行测试test_1。我想将这两个函数重构为一个函数display_pane_2

lambdademo.py:

def display_pane_1():
    display_register(template_1)


def template_1():
    return 'hello mum'


def display_pane_2():
    display_register(lambda: 'hello mum')


def display_register(template):
    print(template())
Run Code Online (Sandbox Code Playgroud)

test_lambdademo.py

import unittest
import unittest.mock as mock

import lambdademo


class TestLambda1(unittest.TestCase):
    def setUp(self):
        p = mock.patch('lambdademo.display_register')
        self.mock_display_register = p.start()
        self.addCleanup(p.stop)

    def test_1(self):
        lambdademo.display_pane_1()
        self.mock_display_register.assert_called_with(lambdademo.template_1)

    def test_2(self):
        lambdademo.display_pane_2()
        self.mock_display_register.assert_called_with('????????')
Run Code Online (Sandbox Code Playgroud)

你能帮我写一个有效的测试吗display_pane_2?我想测试完整的 lambda 表达式,即lambda x: 'hell mum'应该失败。

我尝试了两种解决方案。

第一个选项是 的简单副本,用 的模拟test_1替换 的参数。我在手册中找不到任何建议我应该如何模拟像 lambda 这样的表达式的内容。如果手册中有的话请告诉我在哪里。lambdademo.template_1lambda

我的第二个选择是在 Stack Overflow 和互联网上进行了更广泛的搜索。缺少“python 表达式单元测试”、“python …

python lambda unit-testing

4
推荐指数
1
解决办法
1万
查看次数

为什么模拟“open”并返回 FileNotFoundError 会引发 AttributeError: __exit__?

open通过加薪进行FileNotFoundError模拟测试AttributeError: __exit__。为什么会发生这种情况以及我可以采取什么措施来解决它?

以下代码打开一个简单的文本文件。如果文件丢失,它会生成一个默认值。它已经通过定期运行进行了检查,并且看起来运行良好。

so_main.py

import os

import so_config


def load_savelocation():
    path = os.path.join(so_config.ROOT, so_config.SAVELOCATION_FN)
    savelocation_path = os.path.normpath(path)
    try:
        with open(savelocation_path) as f:
            so_config.SAVELOCATION_PATH = f.readline()
    except FileNotFoundError:
        so_config.SAVELOCATION_PATH = so_config.ROOT
Run Code Online (Sandbox Code Playgroud)

so_config.py

import os

ROOT, _ = os.path.split(__file__)
SAVELOCATION_PATH = None
SAVELOCATION_FN = 'savelocation.ini'
Run Code Online (Sandbox Code Playgroud)

单元测试则是另一回事。我嘲笑了open中的命令so.maintest_so_main.py有两项测试:一项用于正常打开存在的文件,第二项用于测试处理FileNotFoundError

常规文件打开的第一次测试test_read_path_from_disk_file_into_config_py工作正常。

FileNotFoundError第二个测试失败,因为AttributeError: __exit__. 我可以设置self.mock_open.return_valueFileNotFoundError或我可以将其设置为'garbage'。这没有什么区别。

测试so_main.py

import unittest
import unittest.mock as mock

import …
Run Code Online (Sandbox Code Playgroud)

mocking python-3.x try-except python-unittest

3
推荐指数
1
解决办法
2456
查看次数