Skip to main content

56 posts tagged with "TurboGears"

View All Tags

· 7 min read

楔子

自從聽說了敏捷方法 (Agile programming) 後,一直很想試試這種 "測試先行" 的開發方式. 但是在 python 上前後試過 unitest, doctest, 都不夠 "簡單到會想常常拿來用" 的程度,

今天拿了一份原型寫得差不多的程式,試著寫些測試例子 (test case) 後用 nose 測試工具來測試看看,想不到 nose 還蠻容易使用的.

三步驟使用 nose 開始測試

  1. 安裝或更新 nose

# easy_install -U nose

沒用過 easy_install ? 你該開始試著用了!

  1. 撰寫測試例子 (test case)

打開一個新的資料夾,我們統一在這個新資料夾裡寫主程式與測試例子

將要測試的內容寫入 something.py 這個檔案[註 1]:

> class Hello(object):
> def __init__(self):
> self.template = "hello world"
>
> def render(self):
> return self.template

nose 測試工具識別測試例子的條件,是判斷找到的這個類別或方法的名稱是不是以 "test" 或 "Test" 開頭。如果是的話就當成是測試例子. nose 會自動搜尋子目錄下所有符合的測試例子,並自動開始測試.

因此我們第一個範例程式用的測試例子只要是函式名稱用 'test' 開頭來命名就可以囉,我們命名一個檔案 testsomething.py (這個檔案名稱以 test 開頭與識別測試例子的條件並無關聯,只是慣例上放測試的例子的檔名都會加上 test 字樣), 並在裡面寫下:

testsomething.py:

>
> def test_Hello():
> abc = Hello()
> assert "hello" in abc.render()
>
> def test_foreign():
> abc = Hello()
> assert "bonjour" not in abc.render()

assert 是 nose 用來判斷測試結果的語法。主要有這兩種:

  • assert 片段 in "結果"

  • assert 片段 not in "結果" 對照上面範例,可以得知上面兩者的意思就是:

  • 測試結果 "hello" 字串應該在 abc.render () 回應的結果裡

  • 測試結果 "bonjour" 字串應該不會在 abc.render () 回應的結果裡如果上面任一種情況不符合 assert 敘述,這個測試用例就會回報失敗.

  1. 開始測試

切換到檔案在的檔案目錄下,輸入

# nosetests

結果應該類似這個樣子:

> D:\path\pyfile>nosetests
> ......
> ----------------------------------------------------------------------
> Ran 1 tests in 0.020s
>

OK 那麼如果我們改動了 something.py 中 self.template 變數的內容,在內容裡加上了 "bonjour" 字樣,會發生什麼事情呢?

有測試工具的好處就是我們只要單純地再次運行 nosetests 命令就好了,不用花腦力去判斷或思考:) 我們查看訊息時會看到類似以下的訊息:

> 2, in runTest
> self.testFunc()
> File "D:\path\pyfile\testsomething.py", line 90, in test_Hello
> assert "bonjour" not in abc.render()
> AssertionError
> -----------------
> Ran 1 tests in 0.030s
>
> FAILED (failures=1, errors=1)
>

上面的報告提醒我們有一件錯誤: "bonjour" 字串原本不應該出現在 abc.render () 回應結果中的,但結果中竟然出現了!

所以如果我們的測試用例寫的好,就可以肯定我們剛剛改動 something.py 時出了些問題。測試這件事確實有效!

較好的約定

我們已經知道,只要類別或方法的名稱是以 "test" 或 "Test" 開頭。就會被 nose 當成是測試例子,所以其實在一個小程式中,我們大可把測試例子跟主程式放在同一個檔案裡.

但是當你都還不很確定你在幹什麼的時候,我建議還是將測試例子跟主程式分開。這麼做除了程式不容易搞混之外,在切換檔案時,還可以順便切換撰寫程式與撰寫測試例子時的不同 MindSet.

測試驅動

那麼如果我們想改寫 hello 函式,好讓它可以用法語 "bonjour" 打招呼,我們該怎麼辦? 記得 "測試先行", 考慮加上一個新的測試例子,而不影響原本的功能吧!

加入的測試例子:

>
> def test_bonjour():
> abc = Hello('bonjour')
> assert "bonjour" in abc.render()

接著要做的就是再跑一次 nosetests, 看到這個新的例子跟我們報告錯誤了. OK, 那就開始修改 hello 函式吧![註 2]

其他的測試

nose 支援的測試的方式琳瑯滿目,可以使用 "nosetests -h" 命令來查看支援的項目.

例如另外一個常用的測試方式是使用 doctest: nosetests --with-doctest

那麼 doctest 是什麼樣的測試方式? 又該怎麼使用 doctest 呢?嘿嘿,4 月 OSDC.tw 07 再開講囉:D

我知道這個工具已經快半年了,到今天才有時間,勇氣真的下去嘗試. 讓我白白錯過這樣好用的工具這麼久,應該怪在 nose 太少文件可以參考的頭上吧? 乾脆自己來寫個 "三步驟使用 nose 開始測試" 的簡易文件好了.

註 1: 這篇文章不講怎麼寫 python 程式,這部份請自理:P 註 2: 同註 1, 建議妳逛逛 www.python.org.tw 可以看到更多參考資料

· 2 min read

前幾個禮拜看到 limodou 的 Openbook platform 後弄的 TurboGears 製作書站 screencast (示範影片)

第一個影片裡示範了如何使用 TurboGears 建立一個專案,與如何啟動開發用網頁伺服器. 並展示了如何透過修改模板快速訂製頁面。這個 screencast 中完全使用 TurboGears 預設的 CSS style.

1st. is a quickstart demo with hello world template version (6.5MB)

第二個影片裡示範了如何使用 TurboGears 工具箱 (Toolbox) 中的模型設計工具 (Model Designer)和資料編輯工具 (Catwalk) 來建置 TurboGears 動態內容網站

2nd is Model Designer with Catwalk (7.7MB)

第三個影片中使用到我寫的 TurboGears tgcrud 擴充模組,透過 tgcrud 擴充模組可以很容易地產生類似 Rails 的 scaffold 介面架構。但與 scaffold 不同的是所有 code 都是 implicit 的,更加容易修改.

3rd. is tgcrud, the TG's scaffold (5.2 MB)

感謝 Elvelind Grandin 協助上傳至 TurboGears 網頁空間.

· One min read

晚上剛看到在 TurboGears 的說明文件寫作文件中加上了張圖

這張圖上的口號是:

Onward, Documentation Writers! DID YOU CONTRIBUTE SOMETHING TODAY?

可以翻譯成:

前進吧,(寫手) 同志們 你今天為 (TurboGears 的文件) 革命事業貢獻了些什麼嗎?

TurboGears 用這麼有趣的圖 (萬里大長征) 來徵求貢獻文件,真是很 KUSO 呀...

PS: 這週末 (2/10) 有近期的第二次 TurboGears Doc Sprint 喔.

· 5 min read

好久前使用 Ultra Dev (Dreamweaver 4 網頁編輯器時代的東西) 寫 ASP 網頁時,那時其中一個超方便的功能就是在與伺服器繫結後,選擇一個 "產生詳細頁面" 的 Widget 元件,稍稍做點設定 Dreamweaver 就幫我產生一個包含資料庫表單內容的頁面。用同樣類似的方法就能完成製作新增,刪除網頁等事情。製作一套動態網頁也不用花太久時間.

上禮拜回頭去試試 Ruby On Rails 時覺得 ROR 有得分的一大優點是鷹架產生器 (scaffold).

scaffold 有什麼功能呢?scaffold 可以根據 RoR 的 ORM (Active Record) 來產生對應的 Controller/Template 程式碼,達到能基本的資料建立 / 修改 / 檢視 / 刪除 (Create/Read/Update/Delete, CRUD) 的目的。而且即使在產生出來 scaffold 後再變更資料庫欄位,產生出來的程式仍然可以正確判斷內容。使用感覺頗類似 Django 的 admin 介面或 TurboGears 的 Catwalk / DataController, 但是就可修改性而言我覺得這種作法稍勝一籌.

只是要拿 ROR 的 scaffold 繼續修改也很容易碰上問題. 因為它為了要能自動對應資料庫的改變來反應到 scaffold 介面上,所以產生出來的 code 除了基本大框架可見之外,裡面的內容都被包在不可見的單一函式裡. 要做任何修改時還是得自己大量改寫 scaffold 產生的內容 (不過還是比全自己寫來的快)

要搭一個漂亮的鷹架要多久呢? 我使用 TurboGears 來重現 scaffold 的各種列表增刪修改介面,為了取得最高的重用性,再用 widgets 改寫一遍,運用 TurboGears 現成的 Widget 已經能幫忙處理新增 / 修改表單的生成。弄好這個 CRUD 介面已花了 3 小時,而且還不像 Rails 一樣會自動去抓變動的欄位.

(3 小時?有人開始撇嘴了....)

寫這個介面當然是有目的的. 接下來在開發環境中,我試著將這個 CRUD 介面做成了 TurboGears 的樣板。並透過 tg-admin 加入一個 crud 命令。使用

tg-admin crud [model class name][controller name]

這樣的語法來產生一個包含了 controller 和 template 的資料夾

例如 model 中已經定義了一個 BookMark class, 只要在專案資料夾中輸入

$tg-admin crud BookMark admin

就會在專案資料夾中新增一個 admin 資料夾,在 controller 中使用

from admin import admin 就可以將處理 BookMark 資料的介面導入到網站中.

以後每次要做的只是簡單地修改表單欄位 (Form field) 定義和 list/show 樣板想要顯示的欄位就可以有完整的 CRUD 介面了。整個過程只要幾分鐘 (預設還會自動套用專案預設的 CSS, 啥都不改就蠻漂亮滴 XD).

目前 tg-admin crud 的做法和 ROR 的 Scaffold 最大的不同在於整份產生的介面不管是 controller 或 template 的程式都是明確的,沒有需要修改時就得重寫的黑盒子.

接下來應該是進一步降低要修改的地方,透過 widget 來將重複設定 (無論是 controller/template) 都減到最低程度。達到足夠成熟度再公開.

目前的 crud 樣板在這,已經可以運用了 CRUD Template

· 2 min read

WhatWhat Status is a web application for tracking the status of projects across an organization. It's opensource and able to download from here.

I found this project from the TurboGears book. WhatWhatStatus' default setting is for protegres and MySQL, but not for SQLite. I'd like to share my steps to use SQLite database with WhatWhat Status.

1. check out the source from svn

svn co http://cleverdevil.org/svn/optio/whatwhat/trunk

2. install textile with easy_install command

$ easy_install textile

3. config the dev.cfg file to use sqlite database

enter the whatwhat status folder, edit dev.cfg:

[global]

# WHATWHAT SPECIFIC

whatwhat.uploaddir = '%(current_dir_uri)s/whatwhat/static/files'

# DATABASE

sqlobject.dburi="sqlite://%(current_dir_uri)s/devdata.sqlite"

4. create database by tg-admin sql sql command

$ tg-admin sql sql (or tg-admin sql create)

5. add default user with catwalk

5.1 first you need to start the TurboGears toolbox

$ tg-admin toolbox

5.2. choose the catwalk in browser

5.3 select "Person" in catwalk left side menu

5.4 click "Add Person" button on top of the page

5.5 enter the following informations:

displayname: any name
email: any email
userid: admin
password:21232f297a57a5a743894a0e4a801fc3

Note that the password field is crypted, the verbose password we typed means "admin".

6. Start whatwhat status

run

$ whatwhat-start.py

enter the username/password as "admin", "admin", then click login.

all done!