factory_boy で遭遇したエラー
テストコードでテストデータを作る時に今までは以下のようにしてた。
from unittest import TestCase from models.user import User class TestUser(object): def setUp(self): self._init() def _init(): user = User(name='foo', password='pass') db_session.add(user) db_session.commit() def test_auth_fail(self): ret = User.auth(name='bar', passsord='pass') self.assertFalse(ret)
from datetime import datetime from sqlalchemy import Column, Integer, String, DateTime, Boolean from werkzeug import generate_password_hash, check_password_hash from models.db import Base class User(Base): __tablename__ = 'users' id = Column(Integer, primary_key=True) name = Column(String(50)) password = Column(String(128)) delete_flag = Column(Boolean, default=False) created_at = Column(DateTime, default=datetime.now) updated_at = Column(DateTime, default=datetime.now) def __init__(self, name, password, delete_flag=False): self.name = name self.set_password(password) self.delete_flag = delete_flag
色々自分のコードを見直している所なので、factory_boy を使ってみたら、エラーが起きた。
import factory from factory.alchemy import SQLAlchemyModelFactory from models.db import session from models.user import User class UserFactory(SQLAlchemyModelFactory): FACTORY_FOR = User FACTORY_SESSION = session id = factory.Sequence(lambda n: n) name = factory.Sequence(lambda n: u'User%d' % n) password = factory.Sequence(lambda n: u'pass%d' % n) delete_flag = False
class TestUser(TestCase): def setUp(self): self.create_app() UserFactory(name='foo', password='pass') def test_auth_fail(self): ret = User.auth(name='bar', passsord='pass') self.assertFalse(ret)
これでテストコードを実行したら、以下の様なエラーが発生した。
factory/alchemy.py", line 49, in _create obj = target_class(*args, **kwargs) nose.proxy.TypeError: __init__() got an unexpected keyword argument 'id'
User クラスに __init__ でコンストラクタで追加しているのが原因のよう。
__init__() を削るか、以下の様に FACTORY_HIDDEN_ARGS を追加すれば OK
class UserFactory(SQLAlchemyModelFactory): FACTORY_FOR = User FACTORY_SESSION = session FACTORY_HIDDEN_ARGS = ('id',) id = factory.Sequence(lambda n: n) name = factory.Sequence(lambda n: u'User%d' % n) password = factory.Sequence(lambda n: u'pass%d' % n) delete_flag = False
factory_boy の為に __init__() を削るのは間違ってるので、コンストラクタがある場合は、FACTORY_HIDDEN_ARGS を使うのが良い。