Неожиданный результат теста для тестов хранилища данных, запущенных с носоглотками
У меня есть класс UserRepository, для которого я пишу юнит-тесты
class UserRepository(object):
"""
Repository that handles storage and retrieval of models.User objects
in and from the datastore.
"""
def create(self, user):
"""
Create the given user in the datastore if it doesn't exist yet.
Args:
user: The user to create.
Returns:
The created user.
Raises:
exc.DuplicateEntity: If the desired phonenumber is
already taken.
"""
duplicate_user = models.User.query(models.User.phonenumber == user.phonenumber).fetch()
if duplicate_user:
raise exc.DuplicateEntity()
user.put()
return user
У меня есть эти тесты для этого
class UserServiceTest(unittest.TestCase):
"""Tests for the UserService."""
def setUp(self):
"""
Called before tests are run.
"""
self.user_repo = repositories.UserRepository()
#self.policy = datastore_stub_util.PseudoRandomHRConsistencyPolicy(probability=1)
def test_create(self):
"""
Test if the create method creates a user.
"""
ndb.delete_multi(models.User.query().fetch(keys_only=True))
user = models.User(phonenumber='+31612345678#',
email='tim@castelijns.nl',
password='1234abcd')
ret_user = self.user_repo.create(user)
self.assertEqual(ret_user, user)
def test_create_duplicate_fails(self):
"""
Test if attempting to create a user with an existing phonenumber
fails.
"""
ndb.delete_multi(models.User.query().fetch(keys_only=True))
user = models.User(phonenumber='+31612345678#',
email='tim@castelijns.nl',
password='1234abcd')
self.user_repo.create(user)
with self.assertRaises(exc.DuplicateEntity):
self.user_repo.create(user)
ndb.delete_multi(models.User.query().fetch(keys_only=True))
заключается в удалении существующих пользователей из тестовой среды, чтобы тестовые примеры не влияли друг на друга.
Это пользовательское исключение
class DuplicateEntity(Exception):
"""Exception to raise when trying to create a duplicate entity."""
Я запускаю тесты с
$ nosetests --with-gae
Выводит
======================================================================
FAIL: Test if attempting to create a user with an existing phonenumber
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tests/dal/test_repositories.py", line 53, in test_create_duplicate_fails
self.user_repo.create(user)
AssertionError: DuplicateEntity not raised
----------------------------------------------------------------------
Ran 2 tests in 0.080s
FAILED (failures=1)
Что является неожиданным, поскольку второй вызов.create здесь должен вызвать исключение, так как уже есть пользователь с таким номером телефона.
Я уверен, что код работает, потому что я тестировал его вживую.
Также странно, что если я добавлю вызов.create над оператором with, это вызовет исключение:
self.user_repo.create(user)
self.user_repo.create(user)
with self.assertRaises(exc.DuplicateEntity):
self.user_repo.create(user)
Таким образом, это поднято на 3-м вызове, но не 2-м.
У меня есть ощущение, что это связано с политикой согласованности хранилища данных, как описано здесь:
Класс PseudoRandomHRConsistencyPolicy позволяет контролировать вероятность применения записи перед каждым глобальным (не являющимся предком) запросом. Устанавливая вероятность в 0%, мы даем команду заглушке хранилища данных работать с максимальной степенью возможной согласованности. Максимальная возможная согласованность означает, что записи будут фиксироваться, но всегда не будут применяться, поэтому глобальные (не являющиеся предками) запросы будут постоянно не видеть изменений.
однако я не знаю, как носовые морщины справляются с этим. Это даже настраивается? У носа нет много документации.
Как я могу обойти (или исправить) это?
1 ответ
Ваша проблема в том, что вы используете запрос для проверки на наличие дубликатов, и это не гарантирует работоспособность из-за возможной согласованности. Вы заметите, что все тесты в документе, на который вы ссылались, используют запросы предков, которые гарантируют согласованность.
Мое мнение таково: это ожидаемое и правильное поведение (ошибка AssertionError: DuplicateEntity не возникла) и подчеркивает проблему с вашей моделью / подходом.