ラベル テスト の投稿を表示しています。 すべての投稿を表示
ラベル テスト の投稿を表示しています。 すべての投稿を表示

2009年10月27日火曜日

復習 「ふつうのHaskell」 2章

4797336021

ファイルの行数を数える

countline.hs (p.39)

短かいので do 式は使わずに、

main = getContents >>= \x -> print $ length $ lines x

関数合成を利用すると、(cf. Haskell の関数合成)

main = getContents >>= print . length . lines

 

ファイルの先頭から指定した行数だけ表示

head.hs (p.45)

こちらも do 式を使わず、

main = getContents >>= putStrLn . getlines 10
getlines n = unlines . take n . lines

 

ところで、これは次のようにも書ける。

main = getContents >>= printLines 10
printLines n = putStrLn . unlines . take n . lines

一体どちらのコードがいいのかな?

Introduction to QuickCheck – HaskellWiki によると、

… the side effecting monadic code is mixed in with the pure computation, making it difficult to test without moving entirely into a "black box" IO-based testing model.

先ほどの関数の型を比較すると、

*Main> :t getlines
getlines :: Int -> String -> String
*Main> :t printLines
printLines :: Int -> String -> IO ()

前者のの方が IO モナドを含まず、純粋な関数なのでテストしやすくて良いようだ。

 

ファイルの末尾から指定した行数を表示

tail.hs (p.51)

head.hs と同じようにして、

main = getContents >>= putStrLn . tailLines 3
tailLines n =  unlines . reverse . take n . reverse . lines

 

しかし、tailLines 関数を見ると、関数 lines – unlines, reverse – reverse が対になっており、真ん中に take 関数が置かれているように見える。関数を関数で挟みこむデコレータのような関数を定義してシンプルにできないものか…。(cf. Python のデコレータ式 (1))

次のように関数 f を 関数 x, y で挟む関数を次のように定義してみる。

(***) x y f z = y $ f $ x z

これは関数合成を使った方が見やすいかも。

(***) x y f = y . f . x 

これにより対になる関数を定義。

l = lines *** unlines
r = reverse *** reverse

上記の関数を試してみる。

*Main> l (r $ take 2) "hoge\npiyo\nfuga\n"
"piyo\nfuga\n"

動作したので takeLines を書きなおすと、

tailLines n = l $ r $ take n

関数合成を使うなら、

tailLines = l . r . take

 

全体は、

main = getContents >>= putStrLn . tailLines 3

(***) x y f = y . f . x 

l = lines *** unlines
r = reverse *** reverse

tailLines = l . r . take

うーん、返ってわかりずらくなったような気が… (@_@;)  QQQ

2008年8月25日月曜日

PyScripter で UnitTest を自動で生成

PyScripter では UnitTest を作成するとき、対象となるモジュールからテストの雛形を自動で作成してくれる。

 

方法

UnitTest を作成したいモジュールを開き、メニューより Tools > Unit Test Wizard... を選択する。

080825-002

 

テスト対象のメソッドを選択するダイアログが表示されるので、必要なものをチェックする。

080825-003

 

例えば、上記は HtmlTable.py ファイルの HtmlTable クラスのメソッドから UnitTest を作成しようとしている。必要なメソッドを選択した後、 OK ボタンを押すと次のようなコードが自動的に生成された。

#This file was originally generated by PyScripter's unitest wizard

import unittest
import HtmlTable

class TestHtmlTable(unittest.TestCase):

    def setUp(self): 
        pass

    def tearDown(self): 
        pass

    def testsetCell(self):
        pass

    def testtoHtml(self):
        pass

if __name__ == '__main__':
    unittest.main()

unittest.TestCase のサブクラスとしてテスト用のクラス TestHTmlTablle が作成され、中にテスト対象のメソッドに対応したテスト用の空のメソッドが作成されている。 setUp, tearDown メソッドはテストの前処理・後処理で、後二つは先ほど選択したメソッドに対応したもの。

 

ファイルの保存

まず最初に、自動で作成されたテスト用のモジュールをテスト対象と同じディレクトリに保存すること。これをしないでテストを実行しようとすると、次のようなエラーダイアログが表示されてしまう。

exceptions.ImportError: No module named HtmlTable

 

テスト対象のモジュール名

次に、テスト用のメソッドの中でテスト対象のクラスを利用するには、

モジュールの名前.テスト対象のクラス

というように、必ず「モジュールの名前.」を付けること。これを忘れてテストを実行すると、赤い文字で次のように表示される。

TypeError: 'module' object is not callable

はじめこんな初歩的なミスに全然気がつかず悩んでしまった。 ^^;