调用类方法时,Python Nose2测试未完成

时间:2017-07-23 01:49:40

标签: python python-3.x unit-testing nose nose2

当我运行包括使用setuptools和nose2调用@classmethod的测试时,测试套件没有完成它只是继续运行。但是我已经检查过测试确实通过并到达函数的末尾,测试套件只是没有完成运行。如果我使用decode_auth_token删除测试,它可以正常工作。我能够将它缩小到类方法,因为我测试了其他类方法,它们导致了同样的问题

有谁知道为什么会这样?以下是相关的代码片段,但没有发布太多的代码

我的用户模型中的代码

  @classmethod
  def decode_auth_token(cls, auth_token):
    try:
      payload = jwt.decode(auth_token, config.SECRET_KEY, algorithms=['HS256'])
      # check the hash of what we expect the token to be and token we got to be the same
      if bcrypt.check_password_hash(User.by_id(payload['sub']).api_token_hash, auth_token):
        return payload['sub']
      else:
        return 'Token does not match Api Token.'
    except jwt.ExpiredSignatureError:
      return 'Signature expired. Please log in again.'
    except jwt.InvalidTokenError:
      return 'Invalid Token. Please log in again.'

以下两个函数在调用

时也会导致问题
  @classmethod
  def is_username_taken(cls, username):
    return db.session.query(db.exists().where(User.username==username)).scalar()

  @classmethod
  def is_email_taken(cls, email):
    return db.session.query(db.exists().where(User.email==email)).scalar()

此功能在通过

调用时不会导致问题
@classmethod
def by_username(cls, username):
  return User.query.filter(User.username == username).first()

以下是测试

import unittest
import sys

from . import AppTestCase, API_ROOT
from app.extensions import db, bcrypt
from app.models import User, UserSchema, Location, Company


class TestUserModel(AppTestCase):
  def test_encode_auth_token(self):
    user = User.by_username('jdoe')
    auth_token = user.encode_auth_token(user.id)
    self.assertTrue(isinstance(auth_token, bytes))

  def test_decode_auth_token(self):
    user = User.by_username('jdoe')
    auth_token = user.encode_auth_token(user.id)
    self.assertTrue(isinstance(auth_token, bytes))
    self.assertEqual(User.decode_auth_token(auth_token), user.id)
    print('DONE')

第一个测试工作正常,第二个测试打印出Done并正确解码auth_token,返回正确的用户ID,但不会导致测试套件完成。它只是在打印完成后继续运行。

这是设置脚本,我使用python setup.py test

运行测试
import os
from setuptools import setup, find_packages, Command

# Thanks http://stackoverflow.com/questions/3779915/why-does-python-setup-py-sdist-create-unwanted-project-egg-info-in-project-r
class CleanCommand(Command):
  """Custom clean command to tidy up the project root."""
  user_options = []
  def initialize_options(self):
    pass
  def finalize_options(self):
    pass
  def run(self):
    os.system('rm -vrf ./build ./dist ./*.pyc ./*.tgz ./*.egg-info')

with open('requirements.txt') as f:
    requirements = f.read().splitlines()

setup(
  name="XXX",
  description="XXX",
  version=1.0,
  packages=find_packages(),
  install_requires=requirements,
  include_package_data=True,
  test_suite='nose2.collector.collector',
  tests_require=['nose2'],
  cmdclass={
        'clean': CleanCommand,
    }
)

运行和不停止时的输出

running test
Searching for nose2
Best match: nose2 0.6.5
Processing nose2-0.6.5-py3.6.egg

Using XXX/.eggs/nose2-0.6.5-py3.6.egg
running egg_info
writing doomfist.egg-info/PKG-INFO
writing dependency_links to XXX.egg-info/dependency_links.txt
writing requirements to XXX.egg-info/requires.txt
writing top-level names to XXX.egg-info/top_level.txt
reading manifest file 'XXX.egg-info/SOURCES.txt'
writing manifest file 'XXX.egg-info/SOURCES.txt'
running build_ext
/Users/XXX/anaconda3/envs/XXX/lib/python3.6/site-packages/python_dateutil-2.6.0-py3.6.egg/dateutil/parser.py:50: DeprecationWarning: invalid escape sequence \.
/Users/XXX/anaconda3/envs/XXX/lib/python3.6/site-packages/python_dateutil-2.6.0-py3.6.egg/dateutil/parser.py:50: DeprecationWarning: invalid escape sequence \.
/Users/XXX/anaconda3/envs/XXX/lib/python3.6/site-packages/python_dateutil-2.6.0-py3.6.egg/dateutil/tz/win.py:197: DeprecationWarning: invalid escape sequence \{
/Users/XXX/anaconda3/envs/XXX/lib/python3.6/site-packages/python_dateutil-2.6.0-py3.6.egg/dateutil/tz/win.py:247: DeprecationWarning: invalid escape sequence \{
/Users/XXX/anaconda3/envs/XXX/lib/python3.6/site-packages/python_dateutil-2.6.0-py3.6.egg/dateutil/tz/win.py:197: DeprecationWarning: invalid escape sequence \{
/Users/XXX/anaconda3/envs/XXX/lib/python3.6/site-packages/python_dateutil-2.6.0-py3.6.egg/dateutil/tz/win.py:247: DeprecationWarning: invalid escape sequence \{
NOT running in debug mode
DONE
^]^\[1]    35752 quit       python setup.py test

编辑-----对不起,现在发帖子很大 根据评论中的某人建议,我使用调试器来确定它确实完成了测试。实际上它被卡住的地方是在tearDown()期间。我的以下功能就是陷入困境。

def tearDown(self):
    """Clean db session and drop all tables."""
    db.drop_all()

调试器越来越向下,我确定它最终会卡住

for table, fkcs in collection:
  if table is not None:
    self.traverse_single(table, drop_ok=True, _is_metadata_operation=True)
  else:
    for fkc in fkcs:
    ...

更具体地说,这个方法self.traverse_single(table, drop_ok=True, _is_metadata_operation=True)。我假设它等待发电机返回卡住了?不确定,但下面是我再次卡住之前的最后一行。

> /Users/XXX/anaconda3/envs/XXX/lib/python3.6/site-packages/SQLAlchemy-1.1.11-py3.6-macosx-10.7-x86_64.egg/sqlalchemy/sql/ddl.py(929)visit_table()->None
-> _is_metadata_operation=_is_metadata_operation)
(Pdb) n
--Call--
> /Users/XXX/anaconda3/envs/XXX/lib/python3.6/site-packages/SQLAlchemy-1.1.11-py3.6-macosx-10.7-x86_64.egg/sqlalchemy/sql/visitors.py(150)_visitor_iterator()-><sqlalchemy.s...t 0x112045630>
-> yield v
(Pdb) n
GeneratorExit
> /Users/XXX/anaconda3/envs/XXX/lib/python3.6/site-packages/SQLAlchemy-1.1.11-py3.6-macosx-10.7-x86_64.egg/sqlalchemy/sql/visitors.py(150)_visitor_iterator()-><sqlalchemy.s...t 0x112045630>
-> yield v
(Pdb) l
145         def _visitor_iterator(self):
146             """iterate through this visitor and each 'chained' visitor."""
147     
148             v = self
149             while v:
150  ->             yield v
151                 v = getattr(v, '_next', None)
152     
153         def chain(self, visitor):
154             """'chain' an additional ClauseVisitor onto this ClauseVisitor.
155     
(Pdb) n

我相信它会被困在我的下一张桌子上

from ..helpers import get_current_time
from ..extensions import db, ma
from ..constants import STRING_LEN, DESCRIPTION_LEN
from .worker import WorkerSchema

class Injury(db.Model):

  __tablename__ = "injuries"
  def __repr__(self):
    return '<Injury %r>' % (self.id)

  id            = db.Column(db.Integer, primary_key = True)
  title         = db.Column(db.String(STRING_LEN), nullable=False)
  description   = db.Column(db.String(DESCRIPTION_LEN), nullable=False)
  worker_id     = db.Column(db.Integer, db.ForeignKey('workers.id'))
  created_at    = db.Column(db.DateTime, nullable=False, default = get_current_time)
  updated_at    = db.Column(db.DateTime, nullable=False, default = get_current_time, onupdate=get_current_time)

  # Relationships
  worker = db.relationship('Worker', back_populates='injuries')

  # ================================================================

  # ================================================================
  # methods


  # ================================================================
  # Class methods

  @classmethod
  def by_id(cls, id):
    return cls.query.filter(Injury.id==id).first()

class InjurySchema(ma.Schema):
  class Meta:
    fields = ('id', 'title', 'description', 'worker')

  worker = ma.Nested(WorkerSchema)

1 个答案:

答案 0 :(得分:4)

我能够根据此帖SQLAlchemy blocked on dropping tables

在我的drop_all命令之前添加var user = ''; function createUser(firstName, lastName, email, userName, password ){ this.firstName = firstName; } function user(){ user = new createUser(document.getElementById(firstName).value); //the same as accessing the text of <input value="this is my first name."> console.log(user.firstName); //log the property firstName of the object user. when you put this.firstName inside a function, it turns that into a property of of the variable you save it as. That means you must call it by using the variable and a "." and the property name ex firstName } console.log(user.firstName); 来使其工作
db.session.close()

我仍然需要找到会话开放的原因以及我需要关闭它的地方

相关问题