Python 在Selenium测试中,等待最终一致性传播需要多长时间?

Python 在Selenium测试中,等待最终一致性传播需要多长时间?,python,google-app-engine,selenium-webdriver,Python,Google App Engine,Selenium Webdriver,我正在尝试创建测试,以验证在使用Selenium时我的实体是否保存在数据库中。 当我手动输入表单数据时,代码工作正常,但自动测试失败 当我在代码的post函数中设置断点时,我可以看到保存记录后客户数量发生了变化。 我读 我使用的是一个祖先查询,我认为它具有很强的一致性,所以我不知道为什么会出现这些问题 据我所知,由于最终的一致性,测试失败了,解决这个问题的方法是更改伪随机HRConsistencyPolicy设置 policy = datastore_stub_util.PseudoRandom

我正在尝试创建测试,以验证在使用Selenium时我的实体是否保存在数据库中。 当我手动输入表单数据时,代码工作正常,但自动测试失败

当我在代码的post函数中设置断点时,我可以看到保存记录后客户数量发生了变化。 我读

我使用的是一个祖先查询,我认为它具有很强的一致性,所以我不知道为什么会出现这些问题

据我所知,由于最终的一致性,测试失败了,解决这个问题的方法是更改伪随机HRConsistencyPolicy设置

policy = datastore_stub_util.PseudoRandomHRConsistencyPolicy(probability=1)  
当我再次运行测试时,我得到了相同的错误

还有人建议,如果我等待一段时间,最终的一致性将有时间传播。 这对测试也不起作用

创建这些测试有什么不对

> /Users/Bryan/work/GoogleAppEngine/dermalfillersecrets/main.py(130)post()  
-> customer.put()  
(Pdb) l  
125             customer.phone = self.request.get('id_phone')  
126             customer.zipcode = int(self.request.get('id_zip'))  
127             # show original number of customer to show the code works  
128             starting_customer_count = Customer.query(ancestor=client.key).count()  
129             import pdb; pdb.set_trace()  
130  ->         customer.put()  
131             final_customer_count = Customer.query(ancestor=client.key).count()  
132             import pdb; pdb.set_trace()  
133             query_params = {'leadbook_name': leadbook_name}  
134             self.redirect('/?' + urllib.urlencode(query_params))  
135       
(Pdb) starting_customer_count  
19  
(Pdb) c  
> /Users/Bryan/work/GoogleAppEngine/dermalfillersecrets/main.py(133)post()  
-> query_params = {'leadbook_name': leadbook_name}  
(Pdb) l     
128             starting_customer_count = Customer.query(ancestor=client.key).count()  
129             import pdb; pdb.set_trace()  
130             customer.put()  
131             final_customer_count = Customer.query(ancestor=client.key).count()  
132             import pdb; pdb.set_trace()  
133  ->         query_params = {'leadbook_name': leadbook_name}  
134             self.redirect('/?' + urllib.urlencode(query_params))  
135       
136     config = {}  
137     config['webapp2_extras.sessions'] = {  
138         'secret_key': 'my-super-secret-key',  
(Pdb) final_customer_count  
20  
实体也会显示在数据存储查看器中

然而,我的考试一直不及格

$ nosetests --with-gae    
test_guest_can_submit_contact_info (dermalfillersecrets.functional_tests.NewVisitorTest) ... FAIL  

======================================================================  
FAIL: test_guest_can_submit_contact_info (dermalfillersecrets.functional_tests.NewVisitorTest)  
----------------------------------------------------------------------  
Traceback (most recent call last):  
  File "/Users/Bryan/work/GoogleAppEngine/dermalfillersecrets/functional_tests.py", line 75, in test_guest_can_submit_contact_info  
    self.assertNotEqual(orig_customer_count, final_customer_count)  
AssertionError: 0 == 0  
这是functional_tests.py文件内容:

import os, sys  
sys.path.append("/usr/local/google_appengine")  
sys.path.append("/usr/local/google_appengine/lib/yaml/lib")  
sys.path.append("/usr/local/google_appengine/lib/webapp2-2.5.2")  
sys.path.append("/usr/local/google_appengine/lib/django-1.5")  
sys.path.append("/usr/local/google_appengine/lib/cherrypy")  
sys.path.append("/usr/local/google_appengine/lib/concurrent")  
sys.path.append("/usr/local/google_appengine/lib/docker")  
sys.path.append("/usr/local/google_appengine/lib/requests")  
sys.path.append("/usr/local/google_appengine/lib/websocket")  
sys.path.append("/usr/local/google_appengine/lib/fancy_urllib")  
sys.path.append("/usr/local/google_appengine/lib/antlr3")  

import unittest  
from selenium import webdriver  
from google.appengine.api import memcache  
from google.appengine.ext import db  
from google.appengine.ext import testbed  
import dev_appserver    
from google.appengine.tools.devappserver2 import devappserver2  


class NewVisitorTest(unittest.TestCase):  

    def setUp(self):  
        self.testbed = testbed.Testbed()  
        self.testbed.activate()  
        #self.testbed.setup_env(app_id='dermalfillersecrets')  
        self.testbed.init_user_stub()  
        self.testbed.init_datastore_v3_stub()  
        self.testbed.init_memcache_stub()  

        # setup the dev_appserver  
        APP_CONFIGS = ['app.yaml']  

        self.browser = webdriver.Firefox()  
        self.browser.implicitly_wait(3)  

    def tearDown(self):  
        self.browser.quit()  
        self.testbed.deactivate()  


    def test_guest_can_submit_contact_info(self):  
        from main import Client, Customer  
        # below query didn't work because of eventual consistency  
        #query = Customer.query()  
        client = Client.query( Client.name == "Bryan Wheelock").get()  
        orig_customer_count = Customer.query(ancestor=client.key).count()  
        self.browser.get('http://localhost:8080')  
        self.browser.find_element_by_name('id_name').send_keys("Kallie Wheelock")  
        self.browser.find_element_by_name('id_street').send_keys("123 main st")  
        self.browser.find_element_by_name('id_phone').send_keys('(404)555-1212')  
        self.browser.find_element_by_name('id_zip').send_keys("30306")  
        self.browser.find_element_by_name('submit').submit()  
        # this should return 1 more record   
        import time; time.sleep(10)  
        final_customer_count = Customer.query(ancestor=client.key).count()  
        self.assertNotEqual(orig_customer_count, final_customer_count)  
        assert(Customer.query(Customer.name == "Kallie Wheelock").get())  
        # Delete the Customer record  
        Customer.query(Customer.name =="Kallie Wheelock").delete()import os, sys  
        sys.path.append("/usr/local/google_appengine")  
        sys.path.append("/usr/local/google_appengine/lib/yaml/lib")  
        sys.path.append("/usr/local/google_appengine/lib/webapp2-2.5.2")  
        sys.path.append("/usr/local/google_appengine/lib/django-1.5")  
        sys.path.append("/usr/local/google_appengine/lib/cherrypy")  
        sys.path.append("/usr/local/google_appengine/lib/concurrent")  
        sys.path.append("/usr/local/google_appengine/lib/docker")  
        sys.path.append("/usr/local/google_appengine/lib/requests")  
        sys.path.append("/usr/local/google_appengine/lib/websocket")  
        sys.path.append("/usr/local/google_appengine/lib/fancy_urllib")  
        sys.path.append("/usr/local/google_appengine/lib/antlr3")  

        import unittest  
        from selenium import webdriver  
        from google.appengine.api import memcache  
        from google.appengine.ext import db  
        from google.appengine.ext import testbed  
        import dev_appserver    
        from google.appengine.tools.devappserver2 import devappserver2  


        class NewVisitorTest(unittest.TestCase):  

            def setUp(self):  
                self.testbed = testbed.Testbed()  
                self.testbed.activate()  
                #self.testbed.setup_env(app_id='dermalfillersecrets')  
                self.testbed.init_user_stub()  
                self.testbed.init_datastore_v3_stub()  
                self.testbed.init_memcache_stub()  

                # setup the dev_appserver  
                APP_CONFIGS = ['app.yaml']  

                self.browser = webdriver.Firefox()  
                self.browser.implicitly_wait(3)  

            def tearDown(self):  
                self.browser.quit()  
                self.testbed.deactivate()  

            def test_guest_can_submit_contact_info(self):  
                from main import Client, Customer  

                client = Client.query( Client.name == "Bryan Wheelock").get()  
                orig_customer_count = Customer.query(ancestor=client.key).count()  
                self.browser.get('http://localhost:8080')  
                self.browser.find_element_by_name('id_name').send_keys("Kallie Wheelock")  
                self.browser.find_element_by_name('id_street').send_keys("123 main st")  
                self.browser.find_element_by_name('id_phone').send_keys('(404)555-1212')  
                self.browser.find_element_by_name('id_zip').send_keys("30306")  
                self.browser.find_element_by_name('submit').submit()  
                # this should return 1 more record   
                import time; time.sleep(10)  
                final_customer_count = Customer.query(ancestor=client.key).count()  
                self.assertNotEqual(orig_customer_count, final_customer_count)  
                assert(Customer.query(Customer.name == "Kallie Wheelock").get())  
                # Delete the Customer record  
                Customer.query(Customer.name =="Kallie Wheelock").delete()

你想测试什么

如果您尝试测试保存实体的代码,那么您可以编写一个简单的单元测试:saveentity,检查它是否已保存

如果您试图测试客户机代码,那么引入延迟会打破这种测试的想法。无法保证最终一致性的上限。您的UI代码应该能够处理任何时间延迟-从零到至少几秒钟


例如,如果实体的数量对于用户工作流程的延续很重要,那么大多数应用程序都会阻止UI(例如,显示某种进度条或微调器),直到调用成功完成。如果等待保存此实体不是用户工作流程的一部分,则无需在Selenium中对其进行测试-同样,您可以编写一个简单的单元测试。

您要测试什么

如果您尝试测试保存实体的代码,那么您可以编写一个简单的单元测试:saveentity,检查它是否已保存

如果您试图测试客户机代码,那么引入延迟会打破这种测试的想法。无法保证最终一致性的上限。您的UI代码应该能够处理任何时间延迟-从零到至少几秒钟


例如,如果实体的数量对于用户工作流程的延续很重要,那么大多数应用程序都会阻止UI(例如,显示某种进度条或微调器),直到调用成功完成。如果等待保存此实体不是用户工作流程的一部分,则无需在Selenium中对其进行测试-同样,您可以编写一个简单的单元测试。

您要测试什么

如果您尝试测试保存实体的代码,那么您可以编写一个简单的单元测试:saveentity,检查它是否已保存

如果您试图测试客户机代码,那么引入延迟会打破这种测试的想法。无法保证最终一致性的上限。您的UI代码应该能够处理任何时间延迟-从零到至少几秒钟


例如,如果实体的数量对于用户工作流程的延续很重要,那么大多数应用程序都会阻止UI(例如,显示某种进度条或微调器),直到调用成功完成。如果等待保存此实体不是用户工作流程的一部分,则无需在Selenium中对其进行测试-同样,您可以编写一个简单的单元测试。

您要测试什么

如果您尝试测试保存实体的代码,那么您可以编写一个简单的单元测试:saveentity,检查它是否已保存

如果您试图测试客户机代码,那么引入延迟会打破这种测试的想法。无法保证最终一致性的上限。您的UI代码应该能够处理任何时间延迟-从零到至少几秒钟


例如,如果实体的数量对于用户工作流程的延续很重要,那么大多数应用程序都会阻止UI(例如,显示某种进度条或微调器),直到调用成功完成。如果等待保存此实体不是用户工作流程的一部分,则无需在Selenium中对其进行测试-同样,您可以编写一个简单的单元测试。

我认为问题在于您的测试设置,而不是最终的一致性

数据存储有不同的实例,您需要确保使用了正确的实例:

  • dev_appserver.py有自己的数据存储
  • 测试床也有自己的数据存储
  • 默认情况下,Testbed不访问dev_appserver.py使用的数据存储,反之亦然

    由于Selenium使用dev_appserver.py,因此需要明确告知dev_appserver.py和Testbed使用相同的数据存储

    下面是我的测试设置的一个片段。我不确定它是否会按原样运行,但它应该会让你走上正确的方向

    注意,我还显式地启动和停止dev_appserver.py

    import subprocess, time, os, unittest, shlex
    from google.appengine.ext import db, testbed
    from google.appengine.api import apiproxy_stub, apiproxy_stub_map
    from selenium import webdriver
    
    class SeleniumTest(unittest.TestCase):
    
        def setUp(self):
            # Start the dev server
            cmd = "/.../bin/dev_appserver.py /.../app.yaml --storage_path /tmp/datastore --clear_datastore --skip_sdk_update_check"
            self.dev_appserver = subprocess.Popen(shlex.split(cmd), 
                                                  stdout=subprocess.PIPE)
            time.sleep(2) # Important, let dev_appserver start up
            self.testbed = testbed.Testbed()
            self.testbed.setup_env(app_id="dev~myapp")
            self.testbed.activate()
            self.testbed.init_app_identity_stub()
            self.testbed.init_datastore_v3_stub(
                datastore_file="/tmp/datastore/datastore.db", use_sqlite=True)
            self.testbed.init_taskqueue_stub()
            self.testbed.init_memcache_stub()
            self.testbed.init_blobstore_stub()
            self.testbed.init_user_stub()
            self.testbed.init_mail_stub()
            self.testbed.init_urlfetch_stub()        
            self.taskqueue_stub = apiproxy_stub_map.apiproxy.GetStub('taskqueue')
            self.mail_stub = apiproxy_stub_map.apiproxy.GetStub('mail')
            self.datastore_stub = apiproxy_stub_map.apiproxy.GetStub('datastore_v3')
            # Start the headless browser for Selenium tests
            self.driver = webdriver.Firefox()
    
        def tearDown(self):
            self.testbed.deactivate()
            self.driver.quit()
            self.dev_appserver.terminate()
    

    我认为问题在于您的测试设置,而不是最终的一致性

    数据存储有不同的实例,您需要确保使用了正确的实例:

  • dev_appserver.py有自己的数据存储
  • 测试床也有自己的数据存储
  • 默认情况下,Testbed不访问dev_appserver.py使用的数据存储,反之亦然

    由于Selenium使用dev_appserver.py,因此需要明确告知dev_appserver.py和Testbed使用相同的数据存储

    下面是我的测试设置的一个片段。我不确定它是否会按原样运行,但它应该会让你走上正确的方向

    注意,我还显式地启动和停止dev_appserver.py

    import subprocess, time, os, unittest, shlex
    from google.appengine.ext import db, testbed
    from google.appengine.api import apiproxy_stub, apiproxy_stub_map
    from selenium import webdriver
    
    class SeleniumTest(unittest.TestCase):
    
        def setUp(self):
            # Start the dev server
            cmd = "/.../bin/dev_appserver.py /.../app.yaml --storage_path /tmp/datastore --clear_datastore --skip_sdk_update_check"
            self.dev_appserver = subprocess.Popen(shlex.split(cmd), 
                                                  stdout=subprocess.PIPE)
            time.sleep(2) # Important, let dev_appserver start up
            self.testbed = testbed.Testbed()
            self.testbed.setup_env(app_id="dev~myapp")
            self.testbed.activate()
            self.testbed.init_app_identity_stub()
            self.testbed.init_datastore_v3_stub(
                datastore_file="/tmp/datastore/datastore.db", use_sqlite=True)
            self.testbed.init_taskqueue_stub()
            self.testbed.init_memcache_stub()
            self.testbed.init_blobstore_stub()
            self.testbed.init_user_stub()
            self.testbed.init_mail_stub()
            self.testbed.init_urlfetch_stub()        
            self.taskqueue_stub = apiproxy_stub_map.apiproxy.GetStub('taskqueue')
            self.mail_stub = apiproxy_stub_map.apiproxy.GetStub('mail')
            self.datastore_stub = apiproxy_stub_map.apiproxy.GetStub('datastore_v3')
            # Start the headless browser for Selenium tests
            self.driver = webdriver.Firefox()
    
        def tearDown(self):
            self.testbed.deactivate()
            self.driver.quit()
            self.dev_appserver.terminate()
    

    我认为问题在于您的测试设置,而不是最终的一致性

    数据存储有不同的实例,您需要确保