テスタビリティを向上させる設計 – Iceberg クラスを避けよう
こういうクラス設計をしてテストで private メソッドが使えないという事態に陥った事は無いだろうか?
1 2 3 4 5 |
RuleEavluater + Evaluate(string) - Parse() - HasMoreToken() - GetNextToken() |
これは設計があまり良くなくて異なる機能を 1 つのクラスに詰め込んでしまっているのがいけない。この事を海に半分埋まっている事に例えて「氷山クラス」と言う。さて、Single Responsibility Principle に従ってクラスを整理すると下記の様になる。
1 2 3 4 5 6 7 8 9 10 11 |
RuleEvaluater tokenizer : Tokenizer parser : Parser + Evaluate() Tokenizer + HasMoreTokens() + GetNextToken() Parser + Parse() |
テストは Tokenizer のテストをすれば良い。Tokenizer を利用者に対して完全に隠すなら pImpl パターンで RuleEvaluater を実装しないといけないが。
1 2 3 4 5 6 7 8 9 10 |
TEST(Tokenizer, canParseSpaceDelimtedTokens) { std::string input_string = "1 2 test bar"; Tokenizer tokenizer = Tokenizer(input_string); EXPECT_EQ(tokenizer.GetNextToken(), "1"); EXPECT_EQ(tokenizer.GetNextToken(), "2"); EXPECT_EQ(tokenizer.GetNextToken(), "test"); EXPECT_EQ(tokenizer.GetNextToken(), "bar"); EXPECT_EQ(tokenizer.HasMoreTokens(), false); } |
Single Responsibility Principle に従うと当然クラス数は増えてそのデメリットは IDE 上でコードを追うのにジャンプが増える。まぁそれだけの話でテスタビリティが向上するという様に明らかにメンテナンス性が向上するのでそちらの利の方が多きいと考えるのが普通。
参考:
コメントを残す