Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/327.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 在测试kivy编写的应用程序时,如何与UI交互?_Python_Kivy_Kivy Language - Fatal编程技术网

Python 在测试kivy编写的应用程序时,如何与UI交互?

Python 在测试kivy编写的应用程序时,如何与UI交互?,python,kivy,kivy-language,Python,Kivy,Kivy Language,应用程序是由kivy编写的。 我想通过pytest测试一个函数,但是为了测试这个函数,我需要先初始化这个对象,但是初始化时这个对象需要一些来自UI的东西,但是我正处于测试阶段,所以我不知道如何从UI检索一些东西 这是一个有错误且已被处理的类 class SaltConfig(GridLayout): def check_phone_number_on_first_contact(self, button): s = self.instanciate_ServerMsg(t

应用程序是由kivy编写的。 我想通过pytest测试一个函数,但是为了测试这个函数,我需要先初始化这个对象,但是初始化时这个对象需要一些来自UI的东西,但是我正处于测试阶段,所以我不知道如何从UI检索一些东西

这是一个有错误且已被处理的类

class SaltConfig(GridLayout):
    def check_phone_number_on_first_contact(self, button):
        s = self.instanciate_ServerMsg(tt)

        try:
            s.send()
        except HTTPError as err:
            print("[HTTPError] : " + str(err.code))
            return

        # some code when running without error

    def instanciate_ServerMsg():
        return ServerMsg()
这是一个helper类,它生成前一个类使用的ServerMsg对象

class ServerMsg(OrderedDict):
    def send(self,answerCallback=None):
        #send something to server via urllib.urlopen
这是我的测试代码:

class TestSaltConfig:
    def test_check_phone_number_on_first_contact(self):
        myError = HTTPError(url="http://127.0.0.1", code=500,
                        msg="HTTP Error Occurs", hdrs="donotknow", fp=None)

    mockServerMsg = mock.Mock(spec=ServerMsg)
    mockServerMsg.send.side_effect = myError

    sc = SaltConfig(ds_config_file_missing.data_store)

    def mockreturn():
        return mockServerMsg

    monkeypatch.setattr(sc, 'instanciate_ServerMsg', mockreturn)
    sc.check_phone_number_on_first_contact()
我无法初始化对象,初始化时会抛出AttributeError,因为它需要UI中的一些值

所以我被卡住了

我试图模拟对象,然后将函数修补到原来的对象,但也不起作用,因为函数本身具有与UI相关的逻辑


如何解决?谢谢

我写了一篇关于与一个简单的跑步者一起测试Kivy应用程序的文章-。它与
unittest
一起工作,而不是与
pytest
一起工作,但是重写它应该不难,这样它才适合您的需要。在本文中,我将解释如何“穿透”UI的主循环,这样您就可以愉快地使用此按钮:

button = <button you found in widget tree>
button.dispatch('on_release')
按钮=
按钮。调度('on_release')
还有更多。基本上,你可以用这样的测试做任何事情,你不需要独立测试每个函数。我是说。。。这是一个很好的实践,但是有时候(主要是在测试UI时),你不能把它撕下来放到一个50行的测试中

通过这种方式,您可以做与临时用户在使用应用程序时完全相同的事情,因此您甚至可以发现在测试临时方式时遇到的问题,例如一些奇怪/意外的用户行为

这是骨架:

import unittest

import os
import sys
import time
import os.path as op
from functools import partial
from kivy.clock import Clock

# when you have a test in <root>/tests/test.py
main_path = op.dirname(op.dirname(op.abspath(__file__)))
sys.path.append(main_path)

from main import My


class Test(unittest.TestCase):
    def pause(*args):
        time.sleep(0.000001)

    # main test function
    def run_test(self, app, *args):
        Clock.schedule_interval(self.pause, 0.000001)

        # Do something

        # Comment out if you are editing the test, it'll leave the
        # Window opened.
        app.stop()

    def test_example(self):
        app = My()
        p = partial(self.run_test, app)
        Clock.schedule_once(p, 0.000001)
        app.run()

if __name__ == '__main__':
    unittest.main()
导入单元测试
导入操作系统
导入系统
导入时间
将os.path导入为op
从functools导入部分
从kivy.clock导入时钟
#在/tests/test.py中进行测试时
main\u path=op.dirname(op.dirname(op.abspath(\u文件\u)))
sys.path.append(主路径)
从主导入我的
类测试(unittest.TestCase):
def暂停(*args):
睡眠时间(0.000001)
#主要测试功能
def运行测试(自身、应用程序、*args):
时钟计划间隔(自暂停,0.000001)
#做点什么
#如果您正在编辑测试,它将保留
#窗户开了。
app.stop()
def测试_示例(自身):
app=My()
p=部分(自运行测试,应用程序)
一次时钟计划(p,0.000001)
app.run()
如果uuuu name uuuuuu='\uuuuuuu main\uuuuuuu':
unittest.main()

然而,正如Tomas所说,在可能的情况下,您应该将UI和逻辑分开,或者更好地说,当这是一件高效的事情时。您不想为了测试需要与UI通信的单个功能而模拟整个大型应用程序。

最终成功了,只要完成任务,我认为一定会有一个更优雅的解决方案。这个想法很简单,因为除了
s.send()
语句之外,所有行都只是简单的赋值

然后我们只是模拟原始对象,每当在测试阶段出现一些错误时(因为对象缺少UI中的一些值),我们模拟它,重复这一步骤,直到测试方法能够最终测试函数是否能够处理
HTTPError

在这个例子中,我们只需要模拟一个
PhoneNumber
类,这是幸运的,但有时我们可能需要处理更多,因此显然@KeyWeeUsr的答案对于生产环境来说是一个更理想的选择。但我只是把我的想法列在这里,给那些想要快速解决问题的人

@pytest.fixture
def myHTTPError(request):
    """
    Generating HTTPError with the pass-in parameters 
    from pytest_generate_tests(metafunc)
    """
    httpError = HTTPError(url="http://127.0.0.1", code=request.param,
                          msg="HTTP Error Occurs", hdrs="donotknow", fp=None)
    return httpError

class TestSaltConfig:
    def test_check_phone_number( self, myHTTPError, ds_config_file_missing ):
        """
        Raise an HTTP 500 error, and invoke the original function with this error.
        Test to see if it could pass, if it can't handle, the test will fail.
        The function locates in configs.py, line 211
        This test will run 2 times with different HTTP status code, 404 and 500
        """

        # A setup class used to cover the runtime error
        # since Mock object can't fake properties which create via __init__()
        class PhoneNumber:
            text = "610274598038"

        # Mock the ServerMsg class, and apply the custom 
        # HTTPError to the send() method
        mockServerMsg = mock.Mock(spec=ServerMsg)
        mockServerMsg.send.side_effect = myHTTPError

        # Mock the SaltConfig class and change some of its 
        # members to our custom one
        mockSalt = mock.Mock(spec=SaltConfig)
        mockSalt.phoneNumber = PhoneNumber()
        mockSalt.instanciate_ServerMsg.return_value = mockServerMsg
        mockSalt.dataStore = ds_config_file_missing.data_store

        # Make the check_phone_number_on_first_contact() 
        # to refer the original function
        mockSalt.check_phone_number = SaltConfig.check_phone_number

        # Call the function to do the test
        mockSalt.check_phone_number_on_first_contact(mockSalt, "button")

听起来像是一个设计缺陷。逻辑不应该依赖于UI。这样做的一个原因是,你可以单独测试它。你如何等待一个元素出现?只需轮询小部件树?这将是无效的