Как я могу подтвердить, что объекты сохраняются с помощью возможной согласованности GAE?
Я пытаюсь создать тесты, чтобы убедиться, что мои объекты сохраняются в базе данных. Когда я ставлю точки останова в функции публикации, я вижу, что количество клиентов меняется после сохранения записи. Я прочитал https://cloud.google.com/appengine/docs/python/tools/localunittesting
Из того, что я понял, тесты проваливались из-за возможной согласованности и способа обойти это путем изменения настроек PseudoRandomHRConsistencyPolicy.
policy = datastore_stub_util.PseudoRandomHRConsistencyPolicy(probability=1)
И когда я снова запустил тест, я получил ту же ошибку.
Что я делаю не так с созданием этих тестов?
> /Users/Bryan/work/GoogleAppEngine/dermalfillersecrets/main.py(137)post()
-> customer.put()
(Pdb) l
134 query = Customer.query()
135 orig_customer_count = query.count()
136 import pdb; pdb.set_trace()
137 -> customer.put()
138 import pdb; pdb.set_trace()
139 query_params = {'leadbook_name': leadbook_name}
140 self.redirect('/?' + urllib.urlencode(query_params))
141
142 config = {}
(Pdb) orig_customer_count
5
(Pdb) c
> /Users/Bryan/work/GoogleAppEngine/dermalfillersecrets/main.py(139)post()
-> query_params = {'leadbook_name': leadbook_name}
(Pdb) l
134 query = Customer.query()
135 orig_customer_count = query.count()
136 import pdb; pdb.set_trace()
137 customer.put()
138 import pdb; pdb.set_trace()
139 -> query_params = {'leadbook_name': leadbook_name}
140 self.redirect('/?' + urllib.urlencode(query_params))
141
142 config = {}
143 config['webapp2_extras.sessions'] = {
144 'secret_key': 'my-super-secret-key',
(Pdb) query.count()
6
Объекты также отображаются в средстве просмотра хранилища данных.
Однако мой тест не проходит.
$ nosetests --with-gae
F
======================================================================
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 80, in test_guest_can_submit_contact_info
self.assertNotEqual(orig_custs, query.count())
AssertionError: 0 == 0
Это содержимое файла functions_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()
####################################################
# this sets testbed to imitate strong consistency
from google.appengine.datastore import datastore_stub_util
policy = datastore_stub_util.PseudoRandomHRConsistencyPolicy(probability=1)
self.testbed.init_datastore_v3_stub(consistency_policy=policy)
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 Customer
query = Customer.query()
orig_custs = query.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 pdb; pdb.set_trace()
query = Customer.query()
self.assertNotEqual(orig_custs, query.count())
assert(Customer.query(Customer.name == "Kallie Wheelock").get())
# Delete the Customer record
Customer.query(Customer.name =="Kallie Wheelock").delete()
4 ответа
PseudoRandomHRConsistencyPolicy
вам здесь не помогают, потому что ваш тест на селен отправляет живую HTML-форму и последующее обновление базы данных происходит на сервере, который выходит за рамки вашей политики.
То, что вы тестируете здесь - это тестирование от конца до конца, а не сам по себе модульный тест Таким образом, ваш тест на селен должен позаботиться о сценарии реального мира и должен подождать в течение предварительно определенного периода времени, прежде чем сравнивать счетчики.
В строгой / возможной согласованности нет ничего плохого, но дизайн ваших тестов неправильный. Почему вы пытаетесь разобраться с devappserver в своих тестах самостоятельно? Почему вы пытаетесь удалить объекты в конце теста? Каждый тест должен быть изолирован друг от друга и начинаться с пустого хранилища данных с некоторыми возможными инициализациями.
Пожалуйста, используйте последнюю версию плагина NoseGAE. Вот два простых теста на сильную / возможную согласованность:
import unittest
from google.appengine.ext import ndb
from google.appengine.datastore import datastore_stub_util
class Foo(ndb.Model):
pass
class TestEventualConsistency(unittest.TestCase):
nosegae_datastore_v3 = True
nosegae_datastore_v3_kwargs = {
'consistency_policy': datastore_stub_util.PseudoRandomHRConsistencyPolicy(
probability=0)}
def test_eventual_consistency(self):
self.assertEqual(Foo.query().count(), 0)
Foo().put()
self.assertEqual(Foo.query().count(), 0)
class TestStrongConsistency(unittest.TestCase):
nosegae_datastore_v3 = True
nosegae_datastore_v3_kwargs = {
'consistency_policy': datastore_stub_util.PseudoRandomHRConsistencyPolicy(
probability=1)}
def test_strong_consistency(self):
self.assertEqual(Foo.query().count(), 0)
Foo().put()
self.assertEqual(Foo.query().count(), 1)
Обратите внимание, что у меня нет ничего о путях GAE, dev_appserver и т. Д. Вы по-прежнему можете управлять тестовым стендом самостоятельно, но лучше настроить его с помощью nosegae_*. (об этом читайте в документации к плагину)
И, насколько я помню, это будет работать, даже если вы будете программно заполнять свою HTML-форму, но это уже не юнит-тесты.
Запросы в конечном итоге непротиворечивы (если не указан предок), но get
операция всегда последовательна.
Если ваша цель состоит в том, чтобы просто протестировать код для написания сущности, вы можете вставить сущность в этот тест и проверить, можете ли вы извлечь эту сущность, используя ее ключ.
Попробуйте использовать запросы предков, чтобы получить строгую согласованность вместо возможной согласованности. Из документов:
Запросы предков позволяют выполнять строго согласованные запросы к хранилищу данных...
Если это не сработает, я бы попробовал не использовать query
объект, но создать новый во второй раз.
Если это тоже не работает, я думаю, что что-то не так. Я не знаком с тестированием браузера, но я с большим успехом использовал веб-тестирование для тестирования веб-конечных точек и не испытывал проблем с согласованностью во время модульного тестирования.