Неожиданный результат теста для тестов хранилища данных, запущенных с носоглотками

У меня есть класс 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 не возникла) и подчеркивает проблему с вашей моделью / подходом.

Другие вопросы по тегам