第3回 掲示板を作ろう(データモデルの定義とユニットテスト)

田原 悠西

2008/10/10

インターフェイスでスキーマを定義する

 ここまでで、3つのデータモデルをクラスとして定義しました。しかし、これではそれぞれのクラスがどんな情報を扱うのか分からないので、それぞれのクラスに対応するインターフェイスクラスを作ってスキーマを定義しましょう。

 Python自身にはインターフェイスという概念はありませんが、Zope 3は拡張モジュールとしてインターフェイスの機能をPythonに持ち込んでいます。データのスキーマ定義にはインターフェイスを用います。

 掲示板にはタイトルと概要の2つの情報を保存できるようにしましょう。app.pyは次のようになります。

import grok
import zope.interface
import zope.schema

class IMyForum(zope.interface.Interface):

    title = zope.schema.TextLine(title=u'Title')
    description = zope.schema.Text(title=u'Description')

class MyForum(grok.Application, grok.Container):

    grok.implements(IMyForum)

    title = None
    description = None

class Index(grok.View):
    pass # see app_templates/index.pt
app.py

 IMyForumクラスがインターフェイスです。Zope 3の提供するインターフェイスはクラス定義のシンタックスを利用しています。インターフェイスクラスはzope.interface.Interfaceを継承する必要があり、名前はアルファベットのIから始める規則になっています。

 インターフェイスの定義の中でzope.schemaを使ってスキーマの定義をしています。これはRDBMSのCREATE TABLE文のようなもので、データ構造を表しています。

 RDBMSと違ってZopeはオブジェクトデータベースを使っているので、実際に保存される情報はあくまで永続クラスのインスタンスであり、それが必ずしもインターフェイスの定義と一致している必要はないのですが、インターフェイスにはコンポーネントのAPIを保証する役割があるので、正しく定義しておきましょう。

 IMyForumインターフェイスでtitleとdescriptionの2つのスキーマを定義しました。TextLineスキーマは改行なしのUnicodeテキストデータ、Textスキーマは改行ありのUnicodeテキストデータを表します。

 ちなみに、Zope 3の内部ではテキストデータはすべてUnicodeで扱うことになっていますので、スキーマの引数のtitleの値はUnicodeでなければいけません。

 MyForumクラスではIMyForumインターフェイスの定義に準じて、2つのアトリビュートを定義し、grok.implementsで該当のインターフェイスを実装したことを宣言しています。

 次にスレッドのスキーマを定義しましょう。スレッドにはその題目としてタイトルを保存できるようにします。forumthread.pyは次のようになります。

import grok
import zope.interface
import zope.schema

class IForumThread(zope.interface.Interface):

    title = zope.schema.TextLine(title=u'Title')

class ForumThread(grok.Container):

    grok.implements(IForumThread)

    title = None

    def __init__(self, title):
        super(ForumThread, self).__init__()
        self.title = title
forumthread.py

 最後にコメントのスキーマ定義です。匿名の掲示板でコメントには名前と本文を保存できるようにしました。comment.pyは次のようになります。

import grok
import zope.interface
import zope.schema

class IComment(zope.interface.Interface):

    name = zope.schema.TextLine(title=u'Name')

    body = zope.schema.Text(title=u'Body')

class Comment(grok.Container):

    grok.implements(IComment)

    name = None
    body = None

    def __init__(self, name, body):
        super(Comment, self).__init__()
        self.name = name
        self.body = body
comment.py

 以上でスキーマの定義は完成です。これでアプリケーションのデータモデルが完成しました。

ユニットテストを書く

 さて、データモデルが完成したので、簡単なテストを書いておきましょう。ここでは、appモジュール(app.py)のテストの中で、上で作ったデータモデルを簡単にテストすることにします。

 appモジュールをテストするには、app_testsディレクトリを作って、その中にテストコードを置きます。src/myforumディレクトリの中で次のようにコマンドを実行してください。

$ mkdir app_tests
$ cd app_tests
$ touch __init__.py
$ touch test_app.py

 これで、新しく作ったapp_testsディレクトリの中に空の__init__.pyとtest_app.pyファイルができました。__init__.pyファイルはこのディレクトリをPythonのパッケージ化するのに必要なだけなので、中身は空のままで構いません。test_app.pyには次のテストコードを書いてください。

# -*- coding:utf-8 -*-
"""
:Test-Layer: python
"""

import unittest
from myforum.app import MyForum
from myforum.forumthread import ForumThread
from myforum.comment import Comment

class MyForumTest(unittest.TestCase):
    """Test MyForum"""

    def testSimple(self):
        """A very simple test"""
        forum = MyForum()
        forum['thread1'] = ForumThread(title=u'テスト掲示板')
        forum['thread1']['1'] = Comment(name=u'太郎', body=u'こんにちは')
        forum['thread1']['2'] = Comment(name=u'次郎', body=u'さようなら')

    self.assertEqual([comment.body
                    for comment in forum['thread1'].values()],
                    [u'こんにちは', u'さようなら'])
test_app.py

 これは非常に単純なテストで、何もテストしていないようなものですが、引数やシンタックスエラーなどの確認には使えます。このような形でテストコードを追加できるということを覚えておいてください。

 次にmyforumパッケージにユニットテストがあることをgrokに登録しましょう。src/myforumの中にtests.pyを作って、以下のように書いてください。

import grok

test_suite = grok.testing.register_all_tests('myforum')
tests.py

 これで、myforumパッケージ内の全ユニットテストがgrokに登録されて、testコマンドで実行できるようになります。

 src/myforumからMyForumディレクトリに移動して、testコマンドを実行してみましょう。

$ cd ../..
$ ./bin/test
Running tests at level 1
Running unit tests:
  Running:
.
  Ran 1 tests with 0 failures and 0 errors in 0.001 seconds.

 上で作ったユニットテストが実行され、無事テストが成功しました。もし、ここでテストに失敗したならば、書き間違いがあると思います。調べて直してください。

2/3

Index
掲示板を作ろう(データモデルの定義とユニットテスト)
  Page1
grokprojectでアプリケーションの開発環境を作る
データモデルを考える
Page2
インターフェイスでスキーマを定義する
ユニットテストを書く
  Page3
buildout.cfgの調整
Subversionにコミットする

Zope 3とは何ぞや?

 Coding Edgeお勧め記事
いまさらアルゴリズムを学ぶ意味
コーディングに役立つ! アルゴリズムの基本(1)
 コンピュータに「3の倍数と3の付く数字」を判断させるにはどうしたらいいか。発想力を鍛えよう
Zope 3の魅力に迫る
Zope 3とは何ぞや?(1)
 Pythonで書かれたWebアプリケーションフレームワーク「Zope 3」。ほかのソフトウェアとは一体何が違っているのか?
貧弱環境プログラミングのススメ
柴田 淳のコーディング天国
 高性能なIT機器に囲まれた環境でコンピュータの動作原理に触れることは可能だろうか。貧弱なPC上にビットマップの直線をどうやって引く?
Haskellプログラミングの楽しみ方
のんびりHaskell(1)
 関数型言語に分類されるHaskell。C言語などの手続き型言語とまったく異なるプログラミングの世界に踏み出してみよう
ちょっと変わったLisp入門
Gaucheでメタプログラミング(1)
 Lispの一種であるScheme。いくつかある処理系の中でも気軽にスクリプトを書けるGaucheでLispの世界を体験してみよう
  Coding Edgeフォーラムフィード  2.01.00.91


Coding Edge フォーラム 新着記事
@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)

注目のテーマ

>

Coding Edge 記事ランキング

本日 月間