- PR -

ユーティリティクラスをSingletonにしたときのデメリット

投稿者投稿内容
uk
ぬし
会議室デビュー日: 2003/05/20
投稿数: 1155
お住まい・勤務地: 東京都
投稿日時: 2005-07-04 11:03
引用:

それはテストするためにソースを一時的に書き換えるって事ですよね。セッターで置き換えるとかではなくて。


既に書き込みがありますが、そうではありません。
インスタンスを置き換えるのは簡単ですが、クラスを置き換えるのは大変ですよ。呼び出し先の
クラスが完成する前に、呼び出し側のテストをしたい場合、静的メソッドの場合はダミーの
クラスを設置する必要がありますが、静的メソッドの振る舞いを変えてテストする、といった
ことが簡単にはできません。
aa
ぬし
会議室デビュー日: 2004/01/08
投稿数: 299
投稿日時: 2005-07-04 20:13
えーっと、シングルトン自身のクラスのユニットテストじゃなくて、シングルトンを利用しているクラスのユニットテストの話をしていたと思うんですが・・・

シングルトンを利用しているクラスのユニットテストをするときにモックのシングルトンをセットしなきゃいけないでしょ?
koe
大ベテラン
会議室デビュー日: 2003/07/13
投稿数: 198
投稿日時: 2005-07-04 22:18
引用:

aaさんの書き込み (2005-07-04 20:13) より:
えーっと、シングルトン自身のクラスのユニットテストじゃなくて、シングルトンを利用しているクラスのユニットテストの話をしていたと思うんですが・・・


はい、そのつもりです。私が前の投稿で示したコードでは省略しましたが、
testUseConnectionTest()メソッドには、Singletonクラスを使用する
任意のクラスの単体テストコードが入るものと思ってください。

引用:

シングルトンを利用しているクラスのユニットテストをするときにモックのシングルトンをセットしなきゃいけないでしょ?


その通りですが、前の投稿では、モックの準備はstaticメソッドの呼び出し1回だけで
できることを示したつもりです。
この程度は許容範囲と考えていますが、aaさんにとっては違うということでしょうか?
uk
ぬし
会議室デビュー日: 2003/05/20
投稿数: 1155
お住まい・勤務地: 東京都
投稿日時: 2005-07-05 01:30
引用:

aaさんの書き込み (2005-07-04 20:13) より:
えーっと、シングルトン自身のクラスのユニットテストじゃなくて、シングルトンを利用しているクラスのユニットテストの話をしていたと思うんですが・・・

シングルトンを利用しているクラスのユニットテストをするときにモックのシングルトンをセットしなきゃいけないでしょ?


そうですよ。ちなみに私はよくこんなことをします。まず、利用クラスにこんなメソッドを
作っておいて、

コード:
public class Foo {
…
protected Singleton getSingleton() {
return Singleton.getInstance();
}


で、テストコードでこんなことをします。

コード:
public class FooTest extends TestCase {
public void testFoo() {
Foo = new Foo() {
protected Singleton getSingleton() {
return new Singleton() {
…
}
}
}
}


で、テストに適した振る舞いをさせるシングルトンのインスタンスを使わせるようにする
わけです。もちろん匿名内部クラスである必要はありませんが…
aa
ぬし
会議室デビュー日: 2004/01/08
投稿数: 299
投稿日時: 2005-07-05 20:10
失礼。よく見ていませんでした。
ですが、私の美学(?)では、シングルトンなのにprotectedにすることは良しとしません。
抜け穴を作る事になるからです。
言い換えれば、privateであるはずのところをprotectedにソースを変更する事によってユニットテストを可能にしているわけで、セッターを用意して切り替えられるようにしているのとはわけが違うと思うからです。

おかしいですか?
ぽん
大ベテラン
会議室デビュー日: 2003/05/13
投稿数: 157
投稿日時: 2005-07-05 20:22
引用:

aaさんの書き込み (2005-07-05 20:10) より:
失礼。よく見ていませんでした。
ですが、私の美学(?)では、シングルトンなのにprotectedにすることは良しとしません。
抜け穴を作る事になるからです。


下記の様な構成ならどうですか?
コード:

public interface Interface {
String method();
}
public class Singleton implements Interface {
private static final Singleton SINGLETON = new Singleton();

private Singleton() {
}

public static Singleton getInstance() {
return SINGLETON;
}

public String method() {
return "本来の文字列";
}
}
public class MockSingleton implements Interface {
public String method() {
return "テスト用文字列";
}
}
public class Sample {
public void func(final Interface inter) {
final String text = inter.method();
//何らかの処理
}
}
public class SampleTest {
public void testFunc() {
final Sample sample = new Sample();

sample.func(new MockSingleton());
}
}


[追記]
誤解を与えたかもしれないので少し修正

[ メッセージ編集済み 編集者: ぽん 編集日時 2005-07-07 00:37 ]
koe
大ベテラン
会議室デビュー日: 2003/07/13
投稿数: 198
投稿日時: 2005-07-05 21:28
引用:

aaさんの書き込み (2005-07-05 20:10) より:
ですが、私の美学(?)では、シングルトンなのにprotectedにすることは良しとしません。
抜け穴を作る事になるからです。



その考えはよく分かります。私もテスト用に前述の設計をしたり、
テスト用のアクセサメソッドを作ったりしたときは違和感を覚えました。
最近は開き直って、「これはテストの仕方までも考慮された良い設計なのだ!」
と思うようにしています。

アクセス可能性が緩くなるという問題はありますが、テストのしやすさと秤に掛けた結果
今のスタイルを取ることが多くなりました。

引用:

言い換えれば、privateであるはずのところをprotectedにソースを変更する事によってユニットテストを可能にしているわけで、セッターを用意して切り替えられるようにしているのとはわけが違うと思うからです。

おかしいですか?



申し訳ないですが、文章だけでは判断ができませんでした。
外部のクラスからアクセス可能なセッターによりSingletonの動作を切り替え可能で
あるなら、アクセスが可能かどうかという観点からは
Singletonクラスを継承するのと同じように思えます。
よろしければ、aaさんの普段のやり方をコードで示してもらえませんか?
とても興味があります。

>ぼんさん
メソッドベースDI(IoC)って奴ですね。
ただ、Singletonクラス(正確にはInterfaceインタフェースの実装クラス)に
依存する箇所が多い場合、つまり、Sample#func()のような引数にInterfaceを持つ
メソッドが多い場合、Mockを注入する箇所が多くなるため、
Factory MethodパターンやDIコンテナのお世話になる必要がありそうです。
aa
ぬし
会議室デビュー日: 2004/01/08
投稿数: 299
投稿日時: 2005-07-06 20:59
ぽんさんへ

クラスの内部にテスト用のコードを書くのはちょっと違和感がありますね。
引用:

koeさんの書き込み (2005-07-05 21:28) より:
最近は開き直って、「これはテストの仕方までも考慮された良い設計なのだ!」
と思うようにしています。


あはは。すごいですね。
引用:

外部のクラスからアクセス可能なセッターによりSingletonの動作を切り替え可能で
あるなら、アクセスが可能かどうかという観点からは
Singletonクラスを継承するのと同じように思えます。
よろしければ、aaさんの普段のやり方をコードで示してもらえませんか?


別に立派なやり方をしているわけではないです。
普段はデータベースアクセスとかのクラスをシングルトンで実装したりして、ユニットテスト上問題だなあと常日頃思っておりました。

このスレッドで何人かの方が、シングルトンで実装すると、シングルトンを使っているクラスはユニットテストがしやすいという由の発言をされていましたので、私はそうは思わないと書いた次第です。
(シングルトンよりMathクラスにあるような単なるstaticのメソッドの方が単純にテストしやすい。)
#このスレッドの最初はこういう話だったんでしたよね。

未だ試行錯誤状態なのですが、シングルトンをprotectedにしたり内部にテストコードを書いたりするよりかは、DIで実装するのがいいのではないのかなと考えております。
こんな感じです。
コード:

public interface Dao {
public xxx method();
}

public class NormalClass {
public void setDao(Dao dao) { <=ここでセットされるのがシングルトンでもいいわけで。
}
}



[ メッセージ編集済み 編集者: aa 編集日時 2005-07-06 21:03 ]

スキルアップ/キャリアアップ(JOB@IT)