Python Django测试登录失败,除非注释掉或重命名了一个完全不相关、完全不重要的函数

Python Django测试登录失败,除非注释掉或重命名了一个完全不相关、完全不重要的函数,python,django,unit-testing,Python,Django,Unit Testing,我的Django测试代码中出现了一个奇怪的错误 完整代码: from .models import MIN_BIRTH_YEAR from .models import UserProfile from django.contrib.auth.models import User from django.test import TestCase import factory TEST_US

我的Django测试代码中出现了一个奇怪的错误

完整代码:

from .models                    import MIN_BIRTH_YEAR
from .models                    import UserProfile
from django.contrib.auth.models import User
from django.test                import TestCase
import factory

TEST_USERS = []
TEST_PASSWORD = 'password123abc'

class UserProfileFactory(factory.django.DjangoModelFactory):
    class Meta:
        model = UserProfile
    birth_year = factory.Sequence(lambda n: n + MIN_BIRTH_YEAR - 1)

class UserFactory(factory.django.DjangoModelFactory):
    class Meta:
        model = User
    profile = factory.RelatedFactory(UserProfileFactory, 'user')

    username = factory.Sequence(lambda n: 'test_username{}'.format(n))
    first_name = factory.Sequence(lambda n: 'test_first_name{}'.format(n))
    last_name = factory.Sequence(lambda n: 'test_last_name{}'.format(n))
    email = factory.Sequence(lambda n: 'test_email{}@example.com'.format(n))
    password = factory.PostGenerationMethodCall('set_password', TEST_PASSWORD)

def create_insert_test_users():
    for i in range(5):
        TEST_USERS.append(UserFactory.create())

def _test_one_logged_in_user(test_instance, test_user_index):
    """
    In addition to public information, private content for a single
    logged-in user should be somewhere on the page.
    """
    test_instance.client.logout()

    test_user = TEST_USERS[test_user_index]

    print('Attempting to login:')
    profile = test_user.profile
    print('test_user.id=' + str(test_user.id))
    print('   username=' + test_user.username + ', password=' + TEST_PASSWORD)
    print('   first_name=' + test_user.first_name + ', last_name=' + test_user.last_name)
    print('   email=' + test_user.email)
    print('   profile=' + str(profile))
    print('      profile.birth_year=' + str(profile.birth_year))
继续。这就是我说的登录行。此
\u test\u one\u logged\u user
函数由下面倒数第二行(
\u test\u one\u logged\u user(self,0)
)调用:

这个很好用。一切都过去了。但是将
test\u true\u is\u true
的名称更改为
test\u content\u not\u logged\u

def test_content_not_logged_in(self):
    """Public information should be somewhere on the page."""
    self.assertTrue(True)
test\u instance.client.login
现在返回
False
…这将导致下面的断言

test_instance.assertTrue(did_login_succeed)
失败:
AssertionError:False不是真的
。但是,如果注释掉整个函数,它会成功(登录返回
True

如果取消对其进行注释并将其重命名为以下任意一项,则它将正常工作:

  • test\u xcontent\u not\u logged\u\u登录
  • 测试内容未登录
  • 测试未登录
其中任何一项都会失败:

  • test\u ctrue\u为真
  • 测试内容未登录
  • 测试内容未登录
  • 测试内容未登录
  • 测试内容未登录
  • 测试未登录
  • 测试无法登录
  • 测试\u cnot\u登录\u
  • test\u c
(我发现了一些东西,但没有发现任何特别之处。)

这似乎意味着
setUp
函数为
test\u content\u not\u logged\u in
(普通函数)运行一次,然后为
test\u logged\u in\u用户运行一次。这两次运行会导致问题。因此,我对其进行了更改,以便仅当
TEST\u USER
数组为空时才创建用户:

def create_insert_test_users():
    if  len(TEST_USERS) == 0:
        for i in range(5):
            TEST_USERS.append(UserFactory.create())
但它仍然失败,我可以确认它失败,用户id为1:

$ python -Wall manage.py test auth_lifecycle.test__view_main2
/home/jeffy/django_files/django_auth_lifecycle_venv/lib/python3.4/site.py:165: DeprecationWarning: 'U' mode is deprecated
  f = open(fullname, "rU")
/home/jeffy/django_files/django_auth_lifecycle_venv/lib/python3.4/imp.py:32: PendingDeprecationWarning: the imp module is deprecated in favour of importlib; see the module's documentation for alternative uses
  PendingDeprecationWarning)
Creating test database for alias 'default'...
.Attempting to login:
test_user.id=1
   username=test_username1, password=password123abc
   first_name=test_first_name1, last_name=test_last_name1
   email=test_email1@example.com
   profile=test_username1
      profile.birth_year=1887
F
======================================================================
FAIL: test_logged_in_users (auth_lifecycle.test__view_main2.MainPageTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/jeffy/django_files/django_auth_lifecycle/auth_lifecycle/test__view_main2.py", line 74, in test_logged_in_users
    _test_one_logged_in_user(self, 0)
  File "/home/jeffy/django_files/django_auth_lifecycle/auth_lifecycle/test__view_main2.py", line 53, in _test_one_logged_in_user
    test_instance.assertTrue(did_login_succeed)
AssertionError: False is not true

----------------------------------------------------------------------
Ran 2 tests in 0.385s

FAILED (failures=1)
Destroying test database for alias 'default'...

models.py:

"""Defines a single extra user-profile field for the user-authentication
    lifecycle demo project:

    - Birth year, which must be between <link to MIN_BIRTH_YEAR> and
    <link to MAX_BIRTH_YEAR>, inclusive.
"""
from datetime                   import datetime
from django.contrib.auth.models import User
from django.core.exceptions     import ValidationError
from django.db                  import models

OLDEST_EVER_AGE     = 127  #:Equal to `127`
YOUNGEST_ALLOWED_IN_SYSTEM_AGE = 13   #:Equal to `13`
MAX_BIRTH_YEAR      = datetime.now().year - YOUNGEST_ALLOWED_IN_SYSTEM_AGE
"""Most recent allowed birth year for (youngest) users."""
MIN_BIRTH_YEAR      = datetime.now().year - OLDEST_EVER_AGE
"""Most distant allowed birth year for (oldest) users."""

def _validate_birth_year(birth_year_str):
    """Validator for <link to UserProfile.birth_year>, ensuring the
        selected year is between <link to OLDEST_EVER_AGE> and
        <link to MAX_BIRTH_YEAR>, inclusive.
        Raises:
            ValidationError: When the selected year is invalid.

        https://docs.djangoproject.com/en/1.7/ref/validators/

        I am a recovered Hungarian Notation junkie (I come from Java). I
        stopped using it long before I started with Python. In this
        particular function, however, because of the necessary cast, it's
        appropriate.
    """
    birth_year_int = -1
    try:
        birth_year_int = int(str(birth_year_str).strip())
    except TypeError:
        raise ValidationError(u'"{0}" is not an integer'.format(birth_year_str))

    if  not (MIN_BIRTH_YEAR <= birth_year_int <= MAX_BIRTH_YEAR):
        message = (u'{0} is an invalid birth year.'
                   u'Must be between {1} and {2}, inclusive')
        raise ValidationError(message.format(
            birth_year_str, MIN_BIRTH_YEAR, MAX_BIRTH_YEAR))
    #It's all good.

class UserProfile(models.Model):
    """Extra information about a user: Birth year.

        ---NOTES---

        Useful related SQL:
            - `select id from auth_user where username <> 'admin';`
            - `select * from auth_lifecycle_userprofile where user_id=(x,x,...);`
    """
    # This line is required. Links UserProfile to a User model instance.
    user = models.OneToOneField(User, related_name="profile")

    # The additional attributes we wish to include.
    birth_year = models.IntegerField(
        blank=True,
        verbose_name="Year you were born",
        validators=[_validate_birth_year])

    # Override the __str__() method to return out something meaningful
    def __str__(self):
        return self.user.username
”为用户身份验证定义了一个额外的用户配置文件字段
生命周期演示项目:
-出生年份,必须介于和之间
包含全部费用
"""
从日期时间导入日期时间
从django.contrib.auth.models导入用户
从django.core.exceptions导入ValidationError
从django.db导入模型
有史以来最老的年龄=127岁:等于127岁`
系统中允许的最小年龄=13岁:等于'13'`
MAX_BIRTH_YEAR=datetime.now().YEAR-系统中允许的最小年龄
“”“最年轻用户的最近允许出生年份。”“”
MIN_BIRTH_YEAR=datetime.now().YEAR-有史以来最老的年龄
“”“最老用户的最远允许出生年份。”“”
定义验证出生年份(出生年份):
“”“验证程序,确保
所选年份介于和之间
包含全部费用
提出:
ValidationError:当所选年份无效时。
https://docs.djangoproject.com/en/1.7/ref/validators/
我是一个匈牙利符号迷(我来自爪哇)
在我开始使用Python之前很久就停止使用它了
然而,由于必要的强制转换,特定的函数
适当的
"""
出生年份整数=-1
尝试:
出生年份int=int(str(出生年份str.strip())
除类型错误外:
raise ValidationError(u'{0}不是整数)。格式(出生年份)
如果不是(最小出生年份将通过寻找以
test

从文件:

单独的测试是用名称开始的方法定义的 使用字母测试。此命名约定通知测试运行者 关于哪些方法表示测试

因此,当您重命名一个普通函数时,它会改变它是否被视为测试。

将通过查找以
测试开始的方法来识别所有测试

从文件:

单独的测试是用名称开始的方法定义的 使用字母测试。此命名约定通知测试运行者 关于哪些方法表示测试

因此,当您重命名一个普通函数时,它会改变它是否被视为测试。

将通过查找以
测试开始的方法来识别所有测试

从文件:

单独的测试是用名称开始的方法定义的 使用字母测试。此命名约定通知测试运行者 关于哪些方法表示测试

因此,当您重命名一个普通函数时,它会改变它是否被视为测试。

将通过查找以
测试开始的方法来识别所有测试

从文件:

单独的测试是用名称开始的方法定义的 使用字母测试。此命名约定通知测试运行者 关于哪些方法表示测试


因此,当您重命名
一个普通函数时,它会改变它是否被视为测试。

原始代码将
测试用户
存储在本地,并且静态保存的对象在测试之间共享时似乎会导致问题。我天真地认为,本地存储对象很重要,以便比较这意味着我不相信Django或Factory Boy会正确地将它们插入数据库,而且它们可以很好地处理

这是更新后的代码,它只存储数据库中的对象。我还将包含
login
的contents子函数直接移到了底部函数中

from .models                    import MIN_BIRTH_YEAR
from .models                    import UserProfile
from django.contrib.auth.models import User
from django.test                import TestCase
import factory

TEST_PASSWORD = 'password123abc'
TEST_USER_COUNT = 5

class UserProfileFactory(factory.django.DjangoModelFactory):
    class Meta:
        model = UserProfile
    birth_year = factory.Sequence(lambda n: n + MIN_BIRTH_YEAR - 1)

class UserFactory(factory.django.DjangoModelFactory):
    class Meta:
        model = User
    profile = factory.RelatedFactory(UserProfileFactory, 'user')

    username = factory.Sequence(lambda n: 'test_username{}'.format(n))
    #print('username=' + username)
    first_name = factory.Sequence(lambda n: 'test_first_name{}'.format(n))
    last_name = factory.Sequence(lambda n: 'test_last_name{}'.format(n))
    email = factory.Sequence(lambda n: 'test_email{}@example.com'.format(n))
    password = factory.PostGenerationMethodCall('set_password', TEST_PASSWORD)

class MainPageTestCase(TestCase):
    """Tests for the main page."""
    def setUp(self_ignored):
        """Insert test users."""
        #print('a User.objects.count()=' + str(User.objects.count()))

        #http://factoryboy.readthedocs.org/en/latest/reference.html?highlight=create#factory.create_batch
        UserFactory.create_batch(TEST_USER_COUNT)

        #print('b User.objects.count()=' + str(User.objects.count()))
继续:

    def test_ctrue_is_true(self):
        """Public information should be somewhere on the page."""
        self.assertTrue(True)

    def test_some_logged_in_users(self):
        """
        In addition to public information, private content for logged in
        users should also be somewhere on the page.
        """
        for  n in range(2):
            self.client.logout()

            test_user = UserFactory()

            print('Attempting to login:')
            profile = test_user.profile
            print('test_user.id=' + str(test_user.id))
            print('   username=' + test_user.username + ', password=' + TEST_PASSWORD)
            print('   first_name=' + test_user.first_name + ', last_name=' + test_user.last_name)
            print('   email=' + test_user.email)
            print('   profile=' + str(profile))
            print('      profile.birth_year=' + str(profile.birth_year))

            did_login_succeed = self.client.login(
                username=test_user.username,
                password=TEST_PASSWORD)
            self.assertTrue(did_login_succeed)

            ##########################################
            # GET PAGE AND TEST ITS CONTENTS HERE...
            ##########################################

原始代码在本地存储
TEST\u用户
,在测试之间共享时,静态保存的对象似乎会导致问题。我天真地认为在本地存储对象很重要,以便比较数据库和
from .models                    import MIN_BIRTH_YEAR
from .models                    import UserProfile
from django.contrib.auth.models import User
from django.test                import TestCase
import factory

TEST_PASSWORD = 'password123abc'
TEST_USER_COUNT = 5

class UserProfileFactory(factory.django.DjangoModelFactory):
    class Meta:
        model = UserProfile
    birth_year = factory.Sequence(lambda n: n + MIN_BIRTH_YEAR - 1)

class UserFactory(factory.django.DjangoModelFactory):
    class Meta:
        model = User
    profile = factory.RelatedFactory(UserProfileFactory, 'user')

    username = factory.Sequence(lambda n: 'test_username{}'.format(n))
    #print('username=' + username)
    first_name = factory.Sequence(lambda n: 'test_first_name{}'.format(n))
    last_name = factory.Sequence(lambda n: 'test_last_name{}'.format(n))
    email = factory.Sequence(lambda n: 'test_email{}@example.com'.format(n))
    password = factory.PostGenerationMethodCall('set_password', TEST_PASSWORD)

class MainPageTestCase(TestCase):
    """Tests for the main page."""
    def setUp(self_ignored):
        """Insert test users."""
        #print('a User.objects.count()=' + str(User.objects.count()))

        #http://factoryboy.readthedocs.org/en/latest/reference.html?highlight=create#factory.create_batch
        UserFactory.create_batch(TEST_USER_COUNT)

        #print('b User.objects.count()=' + str(User.objects.count()))
    def test_ctrue_is_true(self):
        """Public information should be somewhere on the page."""
        self.assertTrue(True)

    def test_some_logged_in_users(self):
        """
        In addition to public information, private content for logged in
        users should also be somewhere on the page.
        """
        for  n in range(2):
            self.client.logout()

            test_user = UserFactory()

            print('Attempting to login:')
            profile = test_user.profile
            print('test_user.id=' + str(test_user.id))
            print('   username=' + test_user.username + ', password=' + TEST_PASSWORD)
            print('   first_name=' + test_user.first_name + ', last_name=' + test_user.last_name)
            print('   email=' + test_user.email)
            print('   profile=' + str(profile))
            print('      profile.birth_year=' + str(profile.birth_year))

            did_login_succeed = self.client.login(
                username=test_user.username,
                password=TEST_PASSWORD)
            self.assertTrue(did_login_succeed)

            ##########################################
            # GET PAGE AND TEST ITS CONTENTS HERE...
            ##########################################
def create_insert_test_users():
    # global tells python to use the TEST_USERS above, not create a new one
    global TEST_USERS
    TEST_USERS = []
    # Your code here...