私はいくつかのWebアプリケーション用に大規模なバックエンドを開発しています。これは私の最初のpythonとSQLAlchemyプロジェクトですので、私はいくつかのものと混同しています。そして、Pythonのもの(私はとにかくEclipseでpydevを使う)と比べて、JavaプログラミングツールとIDEのものに甘んじていた。私はプロジェクトの構造化とテストの書き方について助けが必要です。私は状況をまず説明します。SQLAlchemy(宣言的スタイル)のpythonプロジェクトを正しく構造化する方法unittests
PyDevでは、私は "ProjectName"というプロジェクト名を付けました。私は現在のフォルダ/パッケージとファイル構造を示しています。
- プロジェクト名
- プロジェクト名
- __init__.py
- some_package
- __init__.py
- Foo.py
- Bar.py
の
- 試験
- unit_tests
- __init__.py
- some_package
- __init__.py
- TestFoo.py
- TestBar.py
- load_tests
- integration_tests私はSQLAlchemyの中で宣言型のスタイルを使用し
- __init__.py
- unit_tests
- プロジェクト名
。 FooとBarはいくつかのクラスで、FooはSQLAlchemy宣言型のBaseとBarを拡張してFooを拡張します。それ `sの「projectname.some_package」の下で、私はこのコードを持っているを__init__.py:だから
engine = create_engine('mysql+mysqldb://user:[email protected]:3306/SomeDataBase', pool_recycle=3600)
Session = sessionmaker(bind=engine)
Base = declarative_base()
を、Fooのは、このベースをインポートし、それを拡張し、バーはFooのをインポートし、それを拡張します。私の最初の質問は、__init__.pyにBaseを格納し、この2つのクラスから始めたのと同じように使うべきですか?このcreate_engineはちょうどそこに一時的なものです、私はconfigファイルを持っていて、そこから設定をロードしたいのですが、どうすればいいですか?どこでBase.metadata.create_all()を呼び出す必要があるので、すべてのデータベーステーブルを一度に作成できますか?その後、私はそのテストクラスのいくつかのテストメソッドを持って、それが正常に動作
def setUp(self):
#create database tables and session object
self.engine = create_engine('mysql+mysqldb://user:[email protected]:3306/SomeDatabase', pool_recycle=3600)
Session = sessionmaker(bind=self.engine)
Foo.metadata.create_all(bind=self.engine)
self.session = Session()
def tearDown(self):
#drop all tables and close session object
self.session.close()
meta = MetaData(self.engine)
meta.reflect()
meta.drop_all()
終了:
は次に、テストクラスで、TestFooで例えば私はこのコードを持っています。
Bar.metadata.create_all(bind=self.engine)
私はて、testbarを実行すると、それはまた、正常に動作:て、testbarではクラスの違いは
Foo.metadata.create_all(bind=self.engine)
があるということです。しかし、両方のテストクラスを選択して実行すると、エラーが発生します。
/usr/local/lib/python2.7/dist-packages/sqlalchemy/ext/declarative.py:1336: SAWarning: The classname 'Foo' is already in the registry of this declarative base, mapped to <class 'projectname.some_package.Foo.Foo'>
_as_declarative(cls, classname, cls.__dict__)
/usr/local/lib/python2.7/dist-packages/sqlalchemy/engine/default.py:330: Warning: Field 'id' doesn't have a default value
cursor.execute(statement, parameters)
ここで問題は何ですか?私は鼻とpydevランナーとテストを実行しようとし、同じエラーが発生します。それから、unit_testsのsome_packageの__init__.pyでデータベーステーブルの作成を移動しようとしましたが、動作させることができませんでした。また、私はPythonのインポートの仕組みについて混乱しています。たとえば、TestBarクラスにFooインポートを追加すると、私はすでに示したものと同様のエラーを取得します。 SQLAlchemyクラスを一度にテストする多くの単体テストをどのように実行できますか?だから、再び、最も重要な問題を抽出する
:
- 正しくSQLAlchemyの宣言型のスタイルとユニットテストを使用してPythonのプロジェクトを構築する方法。私はFooとBarにデータベースと対話する多くのクラスメソッドを持っています。それぞれのクラスの文脈で、私はそれがOKであることを望みますか?
- ここでは、Base宣言的なクラスとそれをプロジェクト全体で適切に使用する方法と、プロジェクト内のどこにいても、(クラス内で宣言的に定義した)すべてのデータベーススキーマを抽出して使用する方法を教えてください。
- SQLAlchemyで単体テストを使い、一度に複数の単体テストを実行するにはどうすればいいですか?
- 他の提案がありましたら、それを自由に追加してください。
ありがとうございました。
ユニットテストの推奨パターンはhttp://docs.sqlalchemy.org/en/latest/orm/session.html#joining-a-session-into-an-external-transactionです。アプリケーションの構造化の例については、http://flask.pocoo.org/docs/patterns/sqlalchemy/やhttps://github.com/Pylons/shootout – zzzeek
を参照してください。この回答を知りたいのですが同じように。私は[基本クラスを分離](http://stackoverflow.com/q/9195801/724357)の問題に遭遇し、すべてのsqlalchemyコードを1つのファイルにダンプする必要があったか、正しく機能しませんでした。 –
一つのBaseファイルをmodel/meta.pyのようないくつかの中央ファイルに入れ、他のすべてのパッケージは "model.meta import Base"からインポートします。一般的に、複数のBaseクラスは必要ありません。 – zzzeek