もう LINQ to XML はいらない(謀略編)

既にいくつかの機能を追加してしまったので、実装は先に進んでいるのですが、ちょっと文字列(string)絡みのところを。

// ルート要素を取得する
   EXElement el = doc / "members";

// person 要素を取得する
   EXElements els = doc / "members" / "person";

このように、きっちりと型に保存してもいいのですが、最近の流行は型推論ですよね。
なので、C# 3.0 の場合は、var を使って

// ルート要素を取得する
   var el = doc / "members";

// person 要素を取得する
   var els = doc / "members" / "person";

のようにしてもいいのですが、今回は【型推論】のアプローチじゃなくて、【厳密な型宣言】を応用していきます。つまりは、暗黙のキャスト(implicit)を使っているように見えて、変換先の型が振る舞いを変えている、という受け側の【型】が重要になるというアプローチです。
型推論の場合は、最初に型が決定していなくて後から決定する場合でも OK ってな感じですが、自分が使いやすい型に当てはめる形で値を受け取る、という違うアプローチなのですね…って、本当に違うのかどうか、よく分からないのですが、なんとなく対照性があるかなぁと。

さて、次のコードを見てください。

// ルート要素を取得する
   string val = doc / "members";

// person 要素を取得する
   string[] vals = doc / "members" / "person";

この場合、string と sting[] 型が明示的に使われています。members 要素の値を文字列で受け取りたい、複数ある person 要素の値を文字列の配列で受け取りたい、という【意図】がこの時点で明確になります。
ここで var の場合を使ってしまうと、この時点では、string に入れようとしているのか、EXElement に入れようとしているのか分かりません。

こんな風に、【型を厳密に】指定することによるメリットが大きいわけです。

# 当然ですが、この技は Ruby や PHP などの型がないスクリプト言語では使えません。もし、型のあるスクリプト言語があれば(私はよく知らないのですが)、このアプローチが取れます。

更に、不思議なアプローチを紹介しましょう。

// person 要素を配列で取得する
   string[] vals = doc / "members" / "person";

// person 要素をひとつ取得する
   string val = doc / "members" / "person";

この例では、doc/members/person の配列あるい文字列を取得します。
同じように指定しているのに、配列で取れたり、文字列だけで取れたりするのは不思議でしょう?

でも、この書き方は XML を解析する側としては、明白なことでもあるのです。
XML からデータを取得する場合、あらかじめ XML のデータ構造が分かっていることが多いのです。DTD を指定されないとしても、大まかな構造が分かっている場合がほとんどでしょう。

そうなれば、/members/person が単数なのか、複数なのかは、プログラミングをするときに決まっていますよね。
なので、どうせ XML 構造を把握しているのであれば、それを利用して、単数の string も同様に取れるようにしてしまうほうが自然です。

# たとえば、ファミレスの店員が、ひとりのお客を目の前にして「ただいま、20名のお客様は入れません」と言うことはない…訳でもないけれど、ほぼ無いですよね。まずは「おひとりでしょうか?」と尋ねるのが自然です。

なので、単数で取るのか、配列で取るのかをプログラミングしているときに分けるのも自然です。っていうのが、このコードの主旨です。

と、長々と書きましたが、実はコードが非常に短いからなのです。EXElements クラスができているので、これを string[] や string にキャストするメソッドを作ります。

public class EXElements : List<EXElement>
{
	/// <summary>
	/// 文字列の配列にキャスト
	/// </summary>
	/// <param name="els"></param>
	/// <param name="tag"></param>
	/// <returns></returns>
	public static implicit operator string[]( EXElements els ) 
	{
	    List<string> items = new List<string>();
	    if (els.Count > 0)
	    {
	        foreach (EXElement el in els)
	        {
	            items.Add(el.Value);
	        }
	    }
	    return items.ToArray();
	}

	/// <summary>
	/// 文字列にキャスト
	/// </summary>
	/// <param name="els"></param>
	/// <returns></returns>
	public static implicit operator string(EXElements els)
	{
	    if (els.Count == 0)
	    {
	        return "";
	    }
	    else
	    {
	        return els[0].Value;
	    }
	}
}

馬鹿馬鹿しいほど、簡単なコードですね。implicit で暗黙にキャストを指定しておいて、キャスト先の string[] あるいは string にあわせるだけです。

さて、お次は比較演算子(==)を多重定義して、属性の値によって抽出をしてみます。

カテゴリー: 開発, C# | もう LINQ to XML はいらない(謀略編) はコメントを受け付けていません

アリスは括弧がお嫌い

アリプラシリーズの python 版…と言いますか、ちょっと C++ との比較。
perl 以外で適当なスクリプト言語を、と思っていたので、ruby にしようか、何にしようかと思っていたのですが、python を使ってみました。

で、ちろっと使ってみて、これはッ!!! と思ったのが括弧が少ないことです。
python 特有のタブ(空白でもOK)で揃える書式は、終わりの括弧を少なくするんですね。これって、XML と SOX の関係に似ていて、

<members>
	<person>
		<name>masuda tomoaki</name>
	</person>
</member>

のように XML では閉じタグが必要なのですが、SOX にはいりません。

members>
	person>
		name>
			masuda tomoaki

先の.NET勉強会でXMLのディスカッションの中で、XML はログ出力のようなものには向かない、と言いましたが、SOX はログ出力には向くのです。何故ならば閉じタグがないからです。

この閉じるという処理は、開始と終了が明確になると同時に、閉じるためには、開かないといけない、という作業が発生します…って、禅問答みたいで、なんだか分かりませんね。

例えば先の XML の例だと、新しく person タグを追加する場合には、

  1. mebers 閉じタグの前に書かないといけない。
  2. person の開始タグと終了タグを書かないといけない。
  3. name タグを挿入しないといけない。

という挿入の作業が発生します。これを SOX の場合では、

  1. person タグを追加する。
  2. name タグを追加する。

という追加の作業だけでいいんですね。この後ろに追加していく感覚は、プログラミングにおいても前から後ろへ書いていくという感覚と一致して、非常にやりやすいのです。
なので、LINQ が from から始まるのもその理由ですね。SQL が SELECT から始まるので若干やりづらいので、いきなり SELECT * FROM から書き始めてから、* 部分を書き直していきます。

さて、python は括弧が少ないので、こんな風に alice が書けます。

import sys
args = sys.argv
argc = len(args)

if argc == 1:
	print "alice don't like parentheses."
	print "please input parameters of this program."
else:
	for i,p in enumerate(args):
		print "%d: %s" % (i,p)

慣れも必要なんでしょうけど、インデントが深くなる時は、「:」を打つルールがあるみたいです(みたいです、と書くのは私が初学者だから)。

で、これを素直に C++ で書き直すと、

#include <iostream>
using namespace std;

// アリスは括弧がお嫌い
int main(int argc, char *argv[] )
{
	if ( argc == 1 ) 
		cout << "Alice は括弧がお嫌い" << endl,
		cout << "何かパラメータを指定してッ!!!" << endl;
	else
		for ( int i=0; i<argc; i++ ) 
			cout << i << ":" << argv[i] << endl;
}

え?何これ?って感じですが、中括弧を省くことができます。
まぁ、if 文や for 文の後の1行には括弧がいらないということは良く知られているのですが(逆に、やっちゃいけないよ、って言われてるし)、でも、「,」演算子はなかなか知られておりませんw。
カンマ演算子はC言語のマクロで良く使うのですが、カンマ演算子を使うと式をつなげられるのですね。なので、if 文の後ろにある 2 行が、何故???って感覚になるのです。なるでしょう?

ちなみに、else と for の間には文が入れられません。for は式ではなくて文だからなのです。なので、意図的に書いて括弧をなくしています。

それから連想で考えたのですが、python には end if というものがない。
VB には End if とか、Next がある。
Ruby にも end がある。
SQL には end がない。
LINQ にも end がない。
LISP には、括弧が必要。

なので、終了が必要ないというのは、先の SOX のように後ろへ後ろへとコードを書くことができるんですね。このあたり、もうちょっと考察をしたら書いていきます。

カテゴリー: 雑談, C++, python | 6件のコメント

現在の通信プロトコルには層がひとつ足りない話

昨日の.NETラボの飲み会で話した「通信プロトコルに層がひとつ足りない」の話をちょっとメモ書き。

Siverlight のサーバーアクセスは WCF だったり、ASP.NET MVC からのデータベースアクセスは Entity Framework だったりする訳ですが、内部的には、TCP/IP を生のプロトコルで通しています。正確には HTTP on TCP/IP ってことで、HTTP プロトコルな訳ですが、alive http であろうと、session 毎に切ってしまう http だろうと、ちとある意味で、アプリケーション層と プロトコル層(TCP/IP層) – 用語は、正確ではないのですが — が直結しているために、データのやり取り(特に Connection や 例外関係)に無理があります。

結論から言うとですね、H さんとか、I さんとか、F さんとか、で業務アプリで通信データのやり取りをすると、必ず、TCP/IP を 2 セッションはります。

TCP/IP は、サーバー/クライアント方式ですから、

Clinet -> Server

の接続が必須なんですね。これを等価にするためには、

Client -> Server
Server <- Clinet

の2セッションが必須になるわけです。何故、2セッション必要なのか、双方向通信にする必要があるのかというと、Server 側はから、なんらかの通知をしたいとき(例外発生、異常発生時)に、Client -> Server の一方向だけだと、Client がポーリングをしていない限り、通知を受け取れないのです。つまり、Client が Get しない限り、Server から緊急通知を受けれないというタイムラグが発生します。

なので、サーバーからクライアントへの通知のために、もう1本コネクションを使います。

で、この2つのセッションですが、それぞれの会社で独自の実装をしています。と言いますか、プロジェクト単位で独自の実装をしています。まぁ、開発標準的なものもあるんですが、結局、ライブラリを使って独自の使い方になっちゃう。

これをデータベースアクセスにして考えてみると、Siverlight の非同期通信と、DB アクセスの同期通信が微妙に交差してしまうのです。

  1. Siverlight で、WPF 経由で Web サーバーをコール
  2. 結果待ちになる
  3. Web サーバーが、DB へ同期通信
  4. Web サーバーが、Silverlight へ WPF 経由で結果を返す。
  5. Silverlight が、イベントを発生させる。

という流れになっています。

Silverlight は、一見、非同期通信をしているように見えますが、データベースアクセス的に同期通信に縛られるんですね。これは、.NET Framework プログラミングの第3版を読んでいて気づいたのですが、Silverlight の通信中に他のことができるようにする、ということと(UX的にという意味で)、DB アクセスをしてデータを拾ってくるという意味とは微妙に異なります。

なので、理想的な非同期通信を書き直すと、

  1. Silverlight で、WPF 経由で Web サーバーをコール
  2. Web サーバーは WPF をキャッシュする
  3. Web サーバーは DB へ同期通信
  4. Web サーバーは WPF キャッシュを利用して、Siverlight 自身へ接続
  5. そしてデータ通信
  6. Siverlight は、イベントを発生させる。

という流れになります。一見、先の流れと同じように見えますが、4 のところで、改めて接続しているところが違います。

1 本目のセッションでは、Silverlight から Web サーバーへの WPF コール
2 本目のセッションでは、Web サーバーから Siverlight へのデータコール

になります。
こうすると、Siverlight のほうは、データ受信待ちのポーリングが必要なくなるので、動作が軽くなります。

で、本来の「セッション」の意味づけとして、等価な双方向通信として、この 2 本のセッションをまとめて「セッション」と呼ぶような層が必要、ということなのです。

擬似コードで言うとこんな感じですね。


private DualConnection _cn = new DualConnection

void Setup() {
	// イベントをセットアップ
	_cn.OnConnectin += OnConnection;
	_cn.OnRecv += OnRecv;
	_cn.OnClose += OnClose;
}
void Connect() {
	_cn = new DualConnection()
	// ホスト名を指定するが、どちらから接続してもOK
	_cn.Open( hostname );
}
void OnConnect() {
	// 相手から接続してきた場合
}
void OnRecv( byte[] data ) {
	// 受信データ
}
void OnClose() {
	// 切断処理
}

という形で定義しておいて、

  • Listen は、いらないので、いきなり OnConnection 後に OnRecv が入ってくる。
  • 送信は普通に _cn.Send のように送る。

という層をひとつ用意します。

マルチコネクションにする場合は、

void OnConnect( string hostname ) {
	// 相手から接続してきた場合
}
void OnRecv( byte[] data, string hostname ) {
	// 受信データ
}

のように、sender 要素を入れておくのも良いのですが、これだと受信側がマルチにならないので、実装的には勝手にスレッドを作成して、スレッド単位で P2P 的に接続するのがよいですね。

このあたりの実装を各社さん、それぞれが作っているので、双方向プロトコル on TCP/IP として実装されたらいいなあとか、なんとか。自分で作るか?

# P2P が似たような実装をしているはずなんですが、ちょっとコードを見たことないので分からず。

カテゴリー: 雑談, C# | 1件のコメント

もう LINQ to XML はいらない(電撃戦)

NUnit の説明用に作ってみたのですが、説明にしてはコードが難しいので、こっちにのほうに公開します。
コードに関しては、たった 400 行弱の実装で、同じぐらいの長さの NUnit のコードがあります。

最初は、あまりテストファーストで作らなかったので、無駄なコードが混じっているのですが、ひとまず作ったときの手順をさらして行きますね。もうちょっとまとめたら codeplex にでも公開します。

まず、基本クラスをざっと設計してしまいます。

class EXDocument {
	XmlDocument _xmldoc ;
}
class EXElement {
	XmlElement _xmlelement ;
}
class EXElement : List<EXElement>
class EXAttr {
	XmlAttribute _xmlattr ;
}
class EXAttrs : List<EXAttr>

これだけですw 内部に XmlDocument/XmlElement を持たせて、それを参照して XPath 風に動かします。
C++ の時は、このあたりの実装も考えていたのですが、C# は面倒なので XML 関係はお任せにします。

[Test]
public void TestRoot()
{
    EXDocument doc = new EXDocument();
    doc.LoadXML(@"
<members>
	<person>masuda</person>
</members>
");
    EXElement el = doc / "members";
    Assert.IsNotNull(el);
    Assert.AreEqual("members", el.Name);
    Assert.AreEqual("", el.Value);

    EXElements els = doc / "members" / "person";
    Assert.IsNotNull(els);
    Assert.AreEqual(1, els.Count);
    el = els[0];
    Assert.IsNotNull(el);
    Assert.AreEqual("person", el.Name);
    Assert.AreEqual("masuda", el.Value);
}

最初のテストケースがこれです。

EXDocument::LoadXML は、単純に XmlDocument::LoadXML を呼び出すだけです。

このあたりは【テストファースト】でもありますが、この回の場合は UI 設計も同時にはいっています。
UI 設計という言葉を使うのは、EXDocument をどのように扱うのか?どのように扱いたいのか?というインターフェースの設計だからです。

XML データを読み込んだ後は、

	// ルート要素を取得する
    EXElement el = doc / "members";

	// person 要素を取得する
    EXElements els = doc / "members" / "person";

という使い方がしたい、という(自分の)要件なのです。

さて、これをコンパイルしようとすると、まずは、「EXDocument と string で / 演算子は使って EXElement に変換できない」というコンパイルエラーがでます。

という訳で、仰せの通り EXDocument クラスに / 演算子を実装します。

public static EXElement operator /(EXDocument doc, string s)
{
    if (doc._documentElement != null)
    {
        if (doc._documentElement._xmlelement.Name == s)
        {
            return doc._documentElement;
        }
        else
        {
            return EXDocument._emptyElement;
        }
    }
    return null;
}

_documentElement を参照しているのが冗長ですが、ルート要素のタグ名と引数の文字列を比較して、マッチしたらルート要素を返す。マッチしなかったら空の要素を返す、ってことにしています。

# 空の要素を返すのは、扱いが便利になる null object パターン(empty object パターン?)です。
# null ポインタを返してエラーにするよりも、何もしないものをさらっと返すほうが、呼び出し側のコードが短くなります。

これだけのコードで、

EXElement el = doc / “members”;

の部分は通ってしまいます。

更に、もうひとつの要件をクリアすためにコンパイルエラーを見ます。
「EXElement と string の / 演算子で、EXElements に変換できない」というコンパイルエラーです。

これも先のコードと同じように EXElement クラスに / 演算子を追加します。

public static EXElements operator /(EXElement el, string tag)
{
    EXElements els = new EXElements();
    foreach ( XmlNode nd in el._xmlelement.ChildNodes ) 
    {
        XmlElement xl = nd as XmlElement;
        if ( xl != null ) {
            if ( xl.Name == tag ) {
                EXElement ne =  el._document.CreateElement();
                ne._xmlelement = xl;
                els.Add(ne);
            }
        }
    }
    return els;
}

ややこしいそうですが、やっていることは大したことはありません。
対応する XmlElement の子要素に対してタグ名にマッチするものをコレクションしているだけです。コレクションがばんばん作られますが、まぁ、中身の XmlElement オブジェクトはポインタとして参照するので、メモリ的には問題ないでしょう。

こんな風にすると、さっくりと、下記の2つのコードがコンパイルできるようになります。

	// ルート要素を取得する
    EXElement el = doc / "members";

	// person 要素を取得する
    EXElements els = doc / "members" / "person";

お次は、EXElement とか EXElements のままだと使いづらいので、string に直接代入できるようにします。

カテゴリー: C#, xUnit | もう LINQ to XML はいらない(電撃戦) はコメントを受け付けていません

もう LINQ to XML はいらない(前哨戦)

昔、10年ぐらい前だったか C++ でこんなアイデアを思いつきました。

<members>
 <person name='masuda' age='40'>masuda tomoaki</person>
 <person name='yamada' age='20'>yamada taro</person>
</members>

こんな風な XML があったときに、

XmlElement *el = doc/members/person@name == "masuda";

のように、XPath 風にデータを取得できたら楽だろう、と思ったわけです。
実際は、members や person は、文字列になるので、

XmlElement *el = doc/"members"/"person"@"name" == "masuda";

な感じでコンパイルが通らないかなぁ、と。これをどうやって実現するかというと、【演算子】のオーバーロード機能を使います。
/ 演算子をオーバーライドして、

list<XmlElement*> operator / ( list<XmlElement*> *els, string )
{
 ...
}

のように演算子の多重定義すればできるかなぁ、と。それで、10 年越しに C# で実現してみました。
残念ながら @ 演算子がないので、% 演算子で代用して、

EXElement el = doc/"members"/"person"%"name" == "masuda";

とすると、name 属性の値の要素が取れます。
更に言えば、

string val = doc/"members"/"person"%"name" == "masuda";

のように string 型の変数に代入することで自動的に “masuda tomoaki” が取れるようになります。
このあたりの自動キャストは implicit で暗黙のキャストを使います。普段はキャストを暗黙にすると問題が発生しそうでやめておくのですが、こんな風に LINQ っぽく書く(あるいは関数言語っぽい書き方)をするおきは、自動キャストをうまく考えておくと、処理する行が短くなります。

# ちなみに == も演算子の多重定義をして、EXElements を返す処理にしていますw

そんな訳で、C# で次のコードを動かせるようにしました。

// person タグをコレクションで取得
EXElements els = doc / "members" / "person";

// ひとつしかないと分かっていれば、単数で取得
EXElements el = doc / "members" / "person";

// どうせだから、直接、文字列に変換してしまう。
string[] vals = doc / "members" / "person";
string val = doc / "members" / "person";

// 比較演算子を使って、マッチングもできる
EXElements els = doc / "members" / "person" % "name" == "masuda";

// 複数の属性で検索したい場合は、ラムダ式を使う。
EXElements els = (doc / "members" / "person").Find( m => m % "name" == "masuda" && m % "age" == "40" )

// 子孫を検索するときは、* 演算子を使う.
EXElements els = doc * "members" / "person" % "name" == "masuda";

こんな感じで、なにやら不思議なものができたので、後でアップします。
ええ、当然のごとく NUnit を使ってテストをしています。と言いますか、この手の複雑なロジックは NUnit を使わないと仕上がりません。

カテゴリー: 開発, C# | もう LINQ to XML はいらない(前哨戦) はコメントを受け付けていません

オレオレmvc に PHPUnit を適用する

そんな訳で、オレオレmvc に PHPUnit を使ってみます。
ま、オレオレ mvc はちょっとパワーアップして CakePHP 風なレイアウトとデバッグ表示に。

oreoraMVC ってことで、基本カラーはオレンジ…と言いますか、実は chocolate 色。
実行クエリなんかも表示されます。

テストケースは、こんな感じで書いていこうかなと。

<?php
set_include_path(get_include_path() . PATH_SEPARATOR . '..');
require_once('lib/config.php');
require_once 'controllers/categories_controller.php';

class TestCategoriesController extends PHPUnit_Framework_TestCase
{
	public function testNewIndex()
	{
		$controller = new CategoriesController();
		$controller->index();
		global $Categories;
		$this->assertEquals(19,sizeof($Categories));

		$this->assertEquals(1,$Categories[0]['Category']['term_id']);
		$this->assertEquals("blog",$Categories[0]['Category']['slug']);
		$this->assertEquals("ブログ",$Categories[0]['Category']['name']);
	}
}
?>

ほら、なんかそれっぽくなっているのが不思議。oreoreMVC はもうちょっとしたら、再度公開します。

カテゴリー: CakePHP, xUnit | オレオレmvc に PHPUnit を適用する はコメントを受け付けていません

PHP on IIS に PHPUnit をインストールする

まず、pear ってのが何者か分からずに苦労したのでメモ。

私の場合、PHP on IIS のインストール先が C:\PHP5.3 なのでコマンドプロンプトで移動。
その後、pear のアップデート。

# PHPUnit を入れるためには、PEAR 1.9.1 が必要なんですが、手元のは PEAR 1.9.0 なので駄目らしい。

windowsにPHPunit入れる – これでも…
http://d.hatena.ne.jp/aqua1127/20101013/1286948514

のあたりを参考にして、

go-pear channel-update pear.php.net

ここで、system|local と聞かれるので local にする。system にすると、c:\windows\pear.ini を作ろうとして失敗するので、local にして、PHPのインストール先 c:\PHP5.3 に pear.ini を作るようにする。

pear upgrade pear

でアップデート。接続にひどく時間がかかるけど、しばらく経つと繋がる。

お次は、phpunit 本体

go-pear channel-discover pear.phpunit.de

pear install phpunit/PHPUnit

でインストール、install 時に随分待たされるけど、しばらく経つと繋がる。

最後に、install failed なんてメッセージが出たら、適宜インストール…なんですが、よくわからん。

phpunit/DbUnit requires package “channel://pear.symfony-project.com/YAML” (version >= 1.0.2)

な形でエラーが出ると、

go-pear channel-discover pear.symfony-project.com
pear install symfony/YAML

な風にインストールするらしいのですが、パッケージ名はどうやって知るのだろうか?

# ちなみに、symfony/YAML は c:\php5 に入れようとして、c:\php5.3 を見てくれない(多分、ピリオドが邪魔をしている)。なので、一度、c:\php5 フォルダを作ってコピーしました。

後は、よくわからないけど

go-pear channel-discover components.ez.no

pear install components.ez.no/ConsoleTools

をインストールしました。

で、再び

go-pear channel-discover pear.phpunit.de

pear install phpunit/PHPUnit

とするとインストール完了。windows 版の場合は

c:\php5.3\phpunit.bat が作成されます(c:\php5.3 のところは各自のインストール先で)

きちんとインストールできたかどうか、試してみる。

PHPUnitのテスト作成と実行
http://php.nice-777.com/PHPUnit/start.html

を読んで ArrayTest.php を作成してみる。

<?php
// require_once 'PHPUnit/Framework.php';
class ArrayTest extends PHPUnit_Framework_TestCase
{
    public function testNewArrayIsEmpty()
    {
        // Create the Array fixture.
        $fixture = array();
 
        // Assert that the size of the Array fixture is 0.
        $this->assertEquals(0, sizeof($fixture));
    }
 
    public function testArrayContainsAnElement()
    {
        // Create the Array fixture.
        $fixture = array();
 
        // Add an element to the Array fixture.
        $fixture[] = 'Element';
 
        // Assert that the size of the Array fixture is 1.
        $this->assertEquals(1, sizeof($fixture));
    }
}
?>

どうやら、先頭の PHPUnit/Framework.php はいらないようです。自動的にインポートされます。

あと、phpunit.bat の設定が悪くて php.exe の起動が.\php.exeになっています。
なので、環境変数 PHPBIN に c:\php5.3\php.exe を設定してやります(あるいはパスを通して、php.exe に書き換えるか)。

D:\work\blog\src\phpunit>phpunit ArrayTest
PHPUnit 3.5.11 by Sebastian Bergmann.

..

Time: 1 second, Memory: 3.00Mb

OK (2 tests, 2 assertions)

D:\work\blog\src\phpunit>

そうすると、めでたく PHPUnit が動きます。

ソースを書き換えて失敗するようにすると、

D:\work\blog\src\phpunit>phpunit ArrayTest
PHPUnit 3.5.11 by Sebastian Bergmann.

.F

Time: 0 seconds, Memory: 3.00Mb

There was 1 failure:

1) ArrayTest::testArrayContainsAnElement
Failed asserting that <integer:1> matches expected <integer:2>.

D:\work\blog\src\phpunit\ArrayTest.php:24

FAILURES!
Tests: 2, Assertions: 2, Failures: 1.

D:\work\blog\src\phpunit>

ちゃんと失敗するので大丈夫そうですね。

~~

余談ですが、

class ArrayTest extends PHPUnit_Framework_TestCase

の継承のところ、このファイル名がちょうど

PEAR/PHPUnit/Framework/TestCase.php

に対応しているのですね。PHP5 から加わった自動でクラスをロードしてくれる機能だと思います(多分)。

カテゴリー: 開発, xUnit | 1件のコメント

単体テストグルグル…な.NET勉強会

一応、こちらでも宣伝をしておきます。
今月の .NETラボ勉強会(2/26 土曜日)で、NUnit を使った単体テストの話をします。

.NETラボ勉強会 2011年2月
http://kokucheese.com/event/index/8415/

単体テストツール NUnit の概略と実践的な導入ということで、

・NUnit が導入しやすい構造設計とはどのようなものか?
・NUnit のテストケースは、どれくらいまで書き込むのか?
ボリュームはどのくらいが適当なのか?
・受け入れテストで NUnit を使う

なところを実践をお話します。

例によって、資料が間に合えば資料があるのですが、まあ、間に合わなければ
コードを直に見せるという形になりますが。

# 来た方の様子を見て、NUnit の概要から始めるか、そのあたりは
# わかっているものとして飛ばして、実践編のほうに進むのかを
# 決めます。

今回は、

■ 会場:日本マイクロソフト品川本社(SGT)31F セミナールーム B
http://www.microsoft.com/japan/mscorp/branch/new/default.mspx

なところで、microsoft さんの転居先になるので、セミナールームを
見たい方はどうぞ、とかなんとか。

カテゴリー: 開発, xUnit | 単体テストグルグル…な.NET勉強会 はコメントを受け付けていません

データコンバートに explicit を使う

C#のあまり知られていない機能シリーズってことで、explicit を使ってデータコンバートしましょうってのを試してみます。と言いますか、linq to xml いらないよもどきを作っている最中に、そういえばキャストもオーバーライドができたよなぁ、ってところで気づきました。

一般的な型のコンバートは↓のようにするのが普通なのですが…

型なしDataTableから型付きDataTableにコピーする方法 | Moonmile Solutions Blog
http://www.moonmile.net/blog/archives/2047

いちいち、何とか.CONV 関数を作るのがうざったいですよね。と言うか、使うときに Conv しているのが、ちょっとってな感じなのです。変換しているのが分かり易いといえば分かり易いのですが、C++ 風に言えば、型から型へキャストっていうのも明示的な変換な訳でして、それを利用します。

まずは、使い方から

private void button3_Click(object sender, EventArgs e)
{
	// データベース接続
	SqlConnection cn = new SqlConnection(@"Data Source=.\sqlexpress;Initial Catalog=mvcdb;Integrated Security=True;MultipleActiveResultSets=True");
	cn.Open();
	DataTable dt = new DataTable();
	SqlDataAdapter da = new SqlDataAdapter(
		"SELECT * FROM TProduct", cn);
	da.Fill(dt);
	// キャストする
	DataTableProduct product = (DataTableProduct)dt; // ★
	dataGridView1.DataSource = product;
}

何をやっているのか、いまいち不明ですがw、★のところで、DataTable から 型付の DataTableProduct に変換しています。ここのところ、普通は converet 関数を作るところなのですが、こんな風に明示的なキャスト(explicit)を使うことができます。

# ちなみに暗黙のキャスト(implicit)を使うこともできるのですが、この場合は convert するのが明確になったほうがいいかなと。

そして、これを実現しているのが↓の仕組みです。

public class DataRowProduct
{
	// プロパティ
	public string id { get; set; }
	public string name { get; set; }
	public int price { get; set; }

	// キャストで変換
	public static explicit operator DataRowProduct(DataRow row)
	{
		DataRowProduct dest = new DataRowProduct();
		foreach (PropertyInfo pi in dest.GetType().GetProperties())
		{
			pi.SetValue( dest, Convert.ChangeType(row[pi.Name], pi.PropertyType),null);
		}
		return dest;
	}
}
public class DataTableProduct : IListSource 
{
	protected List<DataRowProduct> _rows = new List<DataRowProduct>();
	public List<DataRowProduct> Rows
	{
		get { return _rows; }
	}

	public bool ContainsListCollection
	{
		get { return true; }
	}

	public System.Collections.IList GetList()
	{
		return this.Rows;
	}

	// キャストで変換
	public static implicit operator DataTableProduct(DataTable dt)
	{
		DataTableProduct dest = new DataTableProduct();
		foreach (DataRow row in dt.Rows)
		{
			dest.Rows.Add((DataRowProduct)row);
		}
		return dest;
	}
}

DataRowProduct クラスのほうでは、リフレクションを使ってデータの詰め込み、そして、DataTableProduct のほうは、キャストを使ってデータ Rows コレクションにため込んでいます。実は、この convert の時にコピーが発生しているので、あんまりうまくないんですよね。どちらかといえば、Rows コレクションのアクセスのたびに DataTable.Rows から引っ張ってくるっていう技のほうが良いかなぁとも思います。

まぁ、それは兎も角として、キャストもうまく使うと変換の意味が表せるから便利ってな話です。
キャストと convert 関数の違いは、

  • キャストのほうは、変換先が注目される。
  • convert 関数のほうは、変換元にメソッドを追加する。
  • あるいは、convert 関数は、変換先に from メソッドを追加する。

という違いがあります。具体的にコードで示してみると、


DataTable dt ;
// キャストの場合は、左向きが明確になる。
// 変換元は表面上は出てこない
DataTableProduct table = (DataTableProduct)dt;

// 変換元で追加するコンバート関数
// ToInteger なんてのがそう。今回の場合は、DataTable を触れないので無理。
// 実は、C# の拡張メソッドを利用すると実現できたり。
DataTableProduct table = dt.ToDataTableProduct();

// 変換先で追加するコンバート関数
// ParseInt なんてのがそう。
// From メソッドか、Conv メソッドか命名に迷うところ
DataTableProduct table = DataTableProduct.From(dt);

こんな感じにすると、キャストの意味が分かっていれば、キャストのほうが自然かな、と思ったりします。DataTable も DataTableProduct も似た感じのクラスな訳ですから、型から型への変換、というほうが自然に見えます。まぁ、シンタックスシュガーっぽいところはありますが。

カテゴリー: C# | データコンバートに explicit を使う はコメントを受け付けていません

Windows アプリケーションでは NUnit を使える構造設計を

ちょっとメモ的に書き下し

CppUnit やら NUnit やらは、10年前から使っているのですが、これらの単体テストをうまく活用するためにはコツが入ります。と、言うか、うまく活用できるようなプログラミングスタイル、構造設計、進捗管理状態、になっていないとうまく活用できません

これ、経験上ですが、NUnit を導入するときの技術的な問題(NUnitを知っているとか知らないとか、Assert.AreEqual だとかなんとか)よりも障壁が大きかったりします。

いくつか導入時のときに注意するポイントを上げると、

■構造設計が無理なパターン

まず、xUnit 自体、UI を必要としない設計にしないとうまく動きません。例えば、Windows アプリケーションでのボタンクリックのエミュレート、Web サイトでのリストボックスの選択、なんていうのが内部ロジックとべったりくっ付いていると、それだけでうまく活用できません。かつて、Visual Test というテストツールがあったのですが、そこまでやらないとうまく行かないという状態でして、このような手間/お金を掛けるのであれば、構造設計の段階で、単体テストがうまく機能するようにデザインする、という手間が必須になってきます。

必然的に、MVC パターン、少なくとも View の分離をしないと、ロジック部分だけをテストする、ということはできないわけです。

このあたり、プロジェクトの作業コストや設計/実装のスキル具合によるので、難しいところもあり、xUnit がうまく導入できないのは、この構造設計の段階で失敗しているというのが非常に大きいです。

■進捗管理で単体試験の項目を管理したいパターン

アジャイル開発で大雑把に管理していれば問題ないののですが、従来のウォーターフォール開発の場合は、どうしてもコーディング(PG) 単体試験(PT)の進捗を別々に管理したくなります。というか、工程的に PG と PT は別ものだから、項目を上げて進捗率を出すとか、PT 工程は PG の後でないと駄目、なんていうのが必須だったりします。

ご存じのように xUnit の場合は、コーディングとテストが一体になったときに初めて効率的になります。勿論、コーディングを全て終わった段階で、テストコードを書くという分離の方法もできるのですが、大抵は面倒くさくなって Excel シートでの単体試験管理に戻ってしまいます。

xUnit の最大の利点は、再帰テストが非常に簡単にでき、それが自動化されることにありますから、PG と PT が混在となるのが必須になります。なので、これを分離しようとすると、そもそも xUnit の利点を排除してしまうことになり、導入に失敗します。

■プログラミングスタイルの統一

これは構造設計にもあてはまるのですが、ひとりで xUnit を導入しているときは、テストする/テスト省略の境界が分かり易いのですが(そう、テストを省略できるというのも xUnit のメリットのひとつです)、複数名のプロジェクトとなると、何をテストするのか、何をテストしないのかの基準が曖昧になります。スクラムなどのアジャイル開発の場合は、たいてい、コーディングスキルの高い人たちが集まるので、それでも大丈夫なんでしょうが、ウォーターフォール開発に場合はスキルがばらばらな場合が多いので、境界があいまいだと、全体の品質が落ちます(人によって品質がばらばらになるという意味で)。

なので、構造設計をした後、クラス分けをした後に、どのロジックはテストで重視するのか、ほとんどのコンストラクタはテストを省略して良いのか、などを分離させる必要があります。

このあたりは、主にウォーターフォール開発のノウハウになります。標準的なスキルを如何に、標準的なスピードに落とし込めるのか、がウォーターフォール開発の要になるので、できる限りクラスの役割を平準化させます。加えて、標準的に活用するライブラリを準備します。
個人的に、インテル方式と呼んでいます。

逆にアジャイル開発の場合は、ライブラリはリファクタリングでできるので、標準化のプロセスはあまりありません。と言いますか、経験者が集まることが多いので、手間がかからずに自然と標準化されます(逆に、そうならなければ、アジャイル開発自体が失敗しているとも言えます)。

で、念のために書いておきますが、今回お手伝いをしているプロジェクトでは、この要点を確実に抑えて頂きました。なので、多分大丈夫。このあたりマネジメントの極意なんですけど、落とし穴を避ければ、成功するという鉄則ですね。リスク管理という意味で。

カテゴリー: 設計 | Windows アプリケーションでは NUnit を使える構造設計を はコメントを受け付けていません