我似乎仍无法让Nosetest正常运行。 从命令行启动时,dev_appserver运行正常,但是当我尝试从functional_tests.py启动它时,它失败了。
我在setUp()中创建了一个Client实体,但是它无法从测试中访问。
如何在测试中启动dev_appserver进入pdb调试器?
我试图在代码中放入pdb()断点。当代码停止执行时,我无法进入调试器。我甚至不确定如何看到输出。
$ nosetests
INFO 2015-02-24 19:08:56,172 devappserver2.py:726] Skipping SDK update check.
INFO 2015-02-24 19:08:56,242 api_server.py:172] Starting API server at: http://localhost:62049
INFO 2015-02-24 19:08:56,247 dispatcher.py:186] Starting module "default" running at: http://localhost:8080
INFO 2015-02-24 19:08:56,249 admin_server.py:118] Starting admin server at: http://localhost:8000
ERROR 2015-02-24 19:09:00,307 webapp2.py:1552] 'NoneType' object has no attribute 'key'
Traceback (most recent call last):
File "/Users/Bryan/Desktop/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/lib/webapp2-2.5.2/webapp2.py", line 1535, in __call__
rv = self.handle_exception(request, response, e)
File "/Users/Bryan/Desktop/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/lib/webapp2-2.5.2/webapp2.py", line 1529, in __call__
rv = self.router.dispatch(request, response)
File "/Users/Bryan/Desktop/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/lib/webapp2-2.5.2/webapp2.py", line 1278, in default_dispatcher
return route.handler_adapter(request, response)
File "/Users/Bryan/Desktop/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/lib/webapp2-2.5.2/webapp2.py", line 1102, in __call__
return handler.dispatch()
File "/Users/Bryan/work/GoogleAppEngine/dermalfillersecrets/main.py", line 18, in dispatch
webapp2.RequestHandler.dispatch(self)
File "/Users/Bryan/Desktop/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/lib/webapp2-2.5.2/webapp2.py", line 572, in dispatch
return self.handle_exception(e, self.app.debug)
File "/Users/Bryan/Desktop/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/lib/webapp2-2.5.2/webapp2.py", line 570, in dispatch
return method(*args, **kwargs)
File "/Users/Bryan/work/GoogleAppEngine/dermalfillersecrets/main.py", line 95, in get
self.session['client'] = client.key.urlsafe()
AttributeError: 'NoneType' object has no attribute 'key'
INFO 2015-02-24 19:09:00,314 module.py:737] default: "GET / HTTP/1.1" 500 2354
INFO 2015-02-24 19:09:00,377 module.py:737] default: "GET /favicon.ico HTTP/1.1" 200 8348
INFO 2015-02-24 19:09:00,381 module.py:737] default: "GET /favicon.ico HTTP/1.1" 304 -
EINFO 2015-02-24 19:09:08,482 shutdown.py:45] Shutting down.
INFO 2015-02-24 19:09:08,483 api_server.py:588] Applying all pending transactions and saving the datastore
======================================================================
ERROR: 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 88, in test_guest_can_submit_contact_info
self.browser.find_element_by_name('id_name').send_keys("Kallie Wheelock")
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/selenium/webdriver/remote/webdriver.py", line 302, in find_element_by_name
return self.find_element(by=By.NAME, value=name)
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/selenium/webdriver/remote/webdriver.py", line 662, in find_element
{'using': by, 'value': value})['value']
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/selenium/webdriver/remote/webdriver.py", line 173, in execute
self.error_handler.check_response(response)
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/selenium/webdriver/remote/errorhandler.py", line 166, in check_response
raise exception_class(message, screen, stacktrace)
NoSuchElementException: Message: Unable to locate element: {"method":"name","selector":"id_name"}
Stacktrace:
at FirefoxDriver.prototype.findElementInternal_ (file:///var/folders/mw/0y88j8_54bjc93d_lg3120qw0000gp/T/tmpSjWZ6W/extensions/fxdriver@googlecode.com/components/driver-component.js:9641:26)
at fxdriver.Timer.prototype.setTimeout/<.notify (file:///var/folders/mw/0y88j8_54bjc93d_lg3120qw0000gp/T/tmpSjWZ6W/extensions/fxdriver@googlecode.com/components/driver-component.js:548:5)
这是functional_tests.py
中的代码import sys, os, subprocess, time, unittest, shlex
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")
from selenium import webdriver
from google.appengine.api import memcache, apiproxy_stub, apiproxy_stub_map
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):
# Start the dev server
cmd = "/usr/local/bin/dev_appserver.py /Users/Bryan/work/GoogleAppEngine/dermalfillersecrets/app.yaml --port 8080 --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.setup_env(app_id='dermalfillersecrets')
self.testbed.init_user_stub()
# Create a consistency policy with a probability of 1,
# the datastore should be available.
self.policy = datastore_stub_util.PseudoRandomHRConsistencyPolicy(probability=1)
# Initialize the datastore stub with this policy.
self.testbed.init_datastore_v3_stub(datastore_file="/tmp/datastore/datastore.db", use_sqlite=True, consistency_policy=self.policy)
self.testbed.init_memcache_stub()
self.datastore_stub = apiproxy_stub_map.apiproxy.GetStub('datastore_v3')
# setup the dev_appserver
APP_CONFIGS = ['app.yaml']
# setup client to make sure
from main import Client
if not ( Client.query( Client.name == "Bryan Wheelock").get()):
logging.info("create Admin")
client = Client(
email = "bryan@mail.com",
name = "Bryan Wheelock",
street1 = "555 Main St",
street2 = "unit 1",
city = "Atlanta",
zipcode = 99999,
phone = "(888)555-1212"
).put()
# this sleep is to allow eventual consistency to propogate
time.sleep(2)
self.browser = webdriver.Firefox()
self.browser.implicitly_wait(3)
def tearDown(self):
self.browser.quit()
self.testbed.deactivate()
self.dev_appserver.terminate()
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')
time.sleep(5)
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()
# the time delay is to allow eventual consisenency to happen.
time.sleep(4)
assert(Customer.query(Customer.name == "Kallie Wheelock").get())
# this should return 1 more record
final_customer_count = Customer.query(ancestor=client.key).count()
self.assertNotEqual(orig_customer_count, final_customer_count)
# Delete the Customer record
Customer.query(Customer.name =="Kallie Wheelock").delete()
这是main.py中的代码:
import os
import urllib
import logging
from google.appengine.api import users
from google.appengine.ext import ndb
import jinja2
import webapp2
from webapp2_extras import sessions
class BaseHandler(webapp2.RequestHandler):
def dispatch(self):
self.session_store = sessions.get_store(request=self.request)
try:
# dispatch the request
webapp2.RequestHandler.dispatch(self)
finally:
# save all sessions
self.session_store.save_sessions(self.response)
@webapp2.cached_property
def session(self):
# Returns a session using the default cookie key.
return self.session_store.get_session()
JINJA_ENVIRONMENT = jinja2.Environment(
loader = jinja2.FileSystemLoader(os.path.dirname(__file__)),
extensions=['jinja2.ext.autoescape'],
autoescape=True)
DEFAULT_LEADBOOK_NAME = 'whatsmyname'
def leadbook_key(leadbook_name=DEFAULT_LEADBOOK_NAME):
"""Constructs a Datastore key for a LeadBook entity with leadbook_name."""
return ndb.Key('LeadBook', leadbook_name)
class Client(ndb.Model):
email = ndb.StringProperty()
name = ndb.StringProperty(indexed=True)
street1 = ndb.StringProperty()
street2 = ndb.StringProperty()
city = ndb.StringProperty()
zipcode = ndb.IntegerProperty()
phone = ndb.StringProperty()
signup = ndb.DateTimeProperty(auto_now_add=True)
# this just creates a Client to use
if not ( Client.query( Client.name == "Bryan Wheelock").get()):
client = Client(
email = "bryan@mail.com",
name = "Bryan Wheelock",
street1 = "555 Main St",
street2 = "unit 1",
city = "Atlanta",
zipcode = 99999,
phone = "(888)555-1212"
).put()
class Customer(ndb.Model):
# I commented out client property because using Ancestor Query( limited to 1 write per second)
#client = ndb.KeyProperty(kind=Client)
#email = ndb.StringProperty(indexed=True)
name = ndb.StringProperty(indexed=True)
street1 = ndb.StringProperty()
street2 = ndb.StringProperty()
city = ndb.StringProperty()
zipcode = ndb.IntegerProperty()
phone = ndb.StringProperty()
signup = ndb.DateTimeProperty(auto_now_add=True)
class MainPage(BaseHandler):
def get(self):
leadbook_name = self.request.get('leadbook_name',
DEFAULT_LEADBOOK_NAME)
# This should be the Client record that shows the info of the owner of the local clinic
# the question is how do I get the site to show the correct Client?
client = Client.query( Client.name == "Bryan Wheelock").get()
self.session['client'] = client.key.urlsafe()
template_values = {
'client': client,
'leadbook_name': urllib.quote_plus(leadbook_name),
}
template = JINJA_ENVIRONMENT.get_template('index.html')
self.response.write(template.render(template_values))
class LeadBook(BaseHandler):
def post(self):
leadbook_name = self.request.get('leadbook_name',
DEFAULT_LEADBOOK_NAME)
client = ndb.Key(urlsafe=self.session['client']).get()
customer = Customer( parent = client.key)
customer.name = self.request.get('id_name')
customer.street1 = self.request.get('id_street')
customer.phone = self.request.get('id_phone')
customer.zipcode = int(self.request.get('id_zip'))
# show original number of customer to show the code works
starting_customer_count = Customer.query(ancestor=client.key).count()
#import pdb; pdb.set_trace()
customer.put()
# This should return the record
assert(Customer.query(Customer.name == "Kallie Wheelock").get())
final_customer_count = Customer.query(ancestor=client.key).count()
#import pdb; pdb.set_trace()
query_params = {'leadbook_name': leadbook_name}
self.redirect('/?' + urllib.urlencode(query_params))
config = {}
config['webapp2_extras.sessions'] = {
'secret_key': 'my-super-secret-key',
}
application = webapp2.WSGIApplication([
('/', MainPage),
('/sign', LeadBook),
], config = config,
debug=True)
答案 0 :(得分:4)
您的评论暗示了这个问题:
# this sleep is to allow eventual consistency to propogate
这真的不是它的运作方式。最终的一致性与时间无关,它在本地数据存储中的模拟方式甚至更少;在测试中,数据存储区testbed实现了一个策略,初始读取几乎总是失败。该文档说明了如何在测试中tweak the policy;一个快捷方式 - 再次,仅适用于测试但不适用于生产 - 是在保存后执行显式.get(),这将始终使实体可见。