I'm trying to code a unit test of my UserModel class which is the next:
from db import db
from logs import Logger
class UserModel(db.Model):
__tablename__ = 'users'
id = db.Column(db.Integer, primary_key=True)
email = db.Column(db.String(30))
password = db.Column(db.String(30))
recipes = db.relationship(
'RecipeModel',
backref='author',
lazy='dynamic'
)
def __init__(self, email, password):
self.email = email
self.password = password
def save(self):
logger = Logger('save::usermodel::models::flask')
logger.debug('Starting save user in database')
db.session.add(self)
db.session.commit()
@classmethod
def find_by_email(cls, email):
logger = Logger('findbyemail::usermodel::models::flask')
logger.debug('Searchin user by email')
return cls.query.filter_by(email=email).first()
@classmethod
def find_by_id(cls, user_id):
logger = Logger('findbyid::usermodel::models::flask')
logger.debug('Searching user by id')
return cls.query.filter_by(id=user_id).first()
def delete_user(self):
logger = Logger('deleteuser::usermodel::models::flask')
logger.debug('Deleting item')
db.session.delete(self)
db.session.commit()
def __repr__(self):
return f'User: {self.email}'
As you can see; user has a relation "one to many" with recipes. On the other hand; recipes has a "many to many" relation with itself:
from db import db
from logs import Logger
recipes_relationship = db.Table(
'RecipeChild',
db.Column('recipe_relation_id', db.Integer, primary_key=True),
db.Column('parent_recipe_id', db.Integer, db.ForeignKey('recipes.id')),
db.Column('child_recipe_id', db.Integer, db.ForeignKey('recipes.id'))
)
class RecipeModel(db.Model):
__tablename__ = 'recipes'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(30))
instructions = db.Column(db.String(300))
photo = db.Column(db.BLOB)
parent_recipe = db.relationship(
'recipes',
secondary=recipes_relationship,
primaryjoin=id == recipes_relationship.c.child_recipe_id,
secondaryjoin=id == recipes_relationship.c.parent_recipe_id,
backref='child_recipe'
)
ingredients = db.relationship(
'IngredientsRecipesModel',
backref='recipe',
lazy='dynamic'
)
user_id = db.Column(db.Integer, db.ForeignKey('users.id'))
def __init__(self, recipe_entity):
self.name = recipe_entity.name
self.instructions = recipe_entity.instructions
self.user_id = recipe_entity.user_id
self.photo = recipe_entity.photo
@classmethod
def find_by_name(cls, name):
logger = Logger('findbyname::recipemodel::models::flask')
logger.debug('Searchin recipe by name')
return cls.query.filter_by(name=name).first()
def save(self):
logger = Logger('save::recipemodel::models::flask')
logger.debug('Recipe saved in database')
db.session.add(self)
db.session.commit()
def delete(self):
logger = Logger('delete::usermodel::models::flask')
logger.debug('Recipe deleted from database')
db.session.delete(self)
db.session.commit()
To this point everything is Ok and it works as it should be. The problem comes when I trying to code the test for the UserModel class. When I run the test I'm getting the next error:
======================================================================
ERROR: test_user_creation (models.test_user_model.TestUserModel)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/Users/adrian.ferrereses/projects/c-c/back-c-c/models/test_user_model.py", line 21, in setUp
self.session.add(UserModel(self.email, self.password))
File "<string>", line 2, in __init__
File "/Users/adrian.ferrereses/projects/c-c/back-c-c/venv/lib/python3.7/site-packages/sqlalchemy/orm/instrumentation.py", line 376, in _new_state_if_none
state = self._state_constructor(instance, self)
File "/Users/adrian.ferrereses/projects/c-c/back-c-c/venv/lib/python3.7/site-packages/sqlalchemy/util/langhelpers.py", line 855, in __get__
obj.__dict__[self.__name__] = result = self.fget(obj)
File "/Users/adrian.ferrereses/projects/c-c/back-c-c/venv/lib/python3.7/site-packages/sqlalchemy/orm/instrumentation.py", line 202, in _state_constructor
self.dispatch.first_init(self, self.class_)
File "/Users/adrian.ferrereses/projects/c-c/back-c-c/venv/lib/python3.7/site-packages/sqlalchemy/event/attr.py", line 322, in __call__
fn(*args, **kw)
File "/Users/adrian.ferrereses/projects/c-c/back-c-c/venv/lib/python3.7/site-packages/sqlalchemy/orm/mapper.py", line 3360, in _event_on_first_init
configure_mappers()
File "/Users/adrian.ferrereses/projects/c-c/back-c-c/venv/lib/python3.7/site-packages/sqlalchemy/orm/mapper.py", line 3248, in configure_mappers
mapper._post_configure_properties()
File "/Users/adrian.ferrereses/projects/c-c/back-c-c/venv/lib/python3.7/site-packages/sqlalchemy/orm/mapper.py", line 1947, in _post_configure_properties
prop.init()
File "/Users/adrian.ferrereses/projects/c-c/back-c-c/venv/lib/python3.7/site-packages/sqlalchemy/orm/interfaces.py", line 196, in init
self.do_init()
File "/Users/adrian.ferrereses/projects/c-c/back-c-c/venv/lib/python3.7/site-packages/sqlalchemy/orm/relationships.py", line 1913, in do_init
self._process_dependent_arguments()
File "/Users/adrian.ferrereses/projects/c-c/back-c-c/venv/lib/python3.7/site-packages/sqlalchemy/orm/relationships.py", line 1975, in _process_dependent_arguments
self.target = self.entity.persist_selectable
File "/Users/adrian.ferrereses/projects/c-c/back-c-c/venv/lib/python3.7/site-packages/sqlalchemy/util/langhelpers.py", line 855, in __get__
obj.__dict__[self.__name__] = result = self.fget(obj)
File "/Users/adrian.ferrereses/projects/c-c/back-c-c/venv/lib/python3.7/site-packages/sqlalchemy/orm/relationships.py", line 1898, in entity
% (self.key, type(argument))
sqlalchemy.exc.ArgumentError: relationship 'parent_recipe' expects a class or a mapper argument (received: <class 'sqlalchemy.sql.schema.Table'>)
----------------------------------------------------------------------
Ran 1 test in 0.022s
FAILED (errors=1)
There is something that I'm not doing when the test starts which makes that the relation of RecipeModel fails.
This is my test code:
import unittest
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from models.user_model import UserModel
from models.recipe_model import RecipeModel
from db import db
class TestUserModel (unittest.TestCase):
engine = create_engine('sqlite:///:memory:')
Session = sessionmaker(bind=engine)
session = Session()
email = 'pepe@mail.com'
password = '1234'
def setUp(self):
db.metadata.create_all(self.engine)
self.session.add(UserModel(self.email, self.password))
self.session.commit()
def tearDown(self):
db.metadata.drop_all(self.engine)
def test_user_creation(self):
result = self.session.query(UserModel).all()
self.assertEqual(True, True)
If you want to verify the entire project here is the link
Any idea? Thank you very much for your time