こんな感じのしょうもないフォームがあるとする。
DataGridView があり、A列と B列は数値を入力できる列で、C列は A - B の計算結果を表示する。
さて、このフォームには、C列の値が負のとき赤で表示するという振る舞いがあるが、果たしてこれをテスト駆動で書けるだろうか?
TDD に慣れた人なら、普通にテストファーストで書くだろうけど、ハナからできないと決め付けてる人も意外と多い。
そんな人が考えるテストはこんな感じ。
- アプリケーションを起動する。
- A列、B列に値を入力する。
- C列の前景色が変わったことを確認する。
まあ普通の手動の動作確認と同じだけど、これを自動化テストコードとしては書けないから UnitTest は無理と言う。
実際にはそういったテストコードも書けないことはないが、TDD の UnitTest ではそんなのは書く必要ないし、第一、テストの観点も目的も手法も違ってるから、むしろ書いてはいけない。
前に書いた HumbleView の作法でやると、例えばこんな風になる。
[TestFixture]
public class Form2PresenterTest
{
public Form2Presenter presenter;
public Mock<IForm2> mock;
[SetUp]
public void SetUp()
{
this.mock = new Mock<IForm2>();
var view = mock.Object;
this.presenter = new Form2Presenter(view);
}
[Test]
public void SelectStyle_Plus()
{
TestSelectStyle(10, 5, CellStyle.NonNegative);
}
[Test]
public void SelectStyle_Zero()
{
TestSelectStyle(10, 10, CellStyle.NonNegative);
}
[Test]
public void SelectStyle_Minus()
{
TestSelectStyle(10, 20, CellStyle.Negative);
}
public void TestSelectStyle(int a, int b, CellStyle style)
{
//arrange
var rowData = this.presenter.RowDataAt(0);
rowData.A = a;
rowData.B = b;
//act
this.presenter.Update(0);
//assert
mock.Verify(v => v.SetGridStyle(2, 0, style));
}
}
見ての通り、Update()メソッドで行のインデクス(簡単のため0固定とした)を受け取った Presenter が、更新された A 列とB列の値に基づいてスタイルを選んで、セルの位置とともにビューに返すという流れになる。
これを満たす IForm2 と Presenter のコードはこんな感じ
public interface IForm2
{
//・・・略・・・
void GridDataSource(List list);
void SetGridStyle(int col, int row, CellStyle styleId);
}
public class Form2Presenter
{
//・・・略・・・
public void Update(int rowIndex)
{
var rowData = this.list[rowIndex];
var cellStyle = rowData.C < 0 ?
CellStyle.Negative : CellStyle.NonNegative;
this.view.SetGridStyle(2, rowIndex, cellStyle);
}
}
やり方はいくつかあるが、ここでは色を System.Drawing.Color で直接指定する代わりに、列挙値 CellStyle を定めて使っている。この CellStyle 定数と実際にセルに設定する DataGridViewCellStyle オブジェクトのマッピングを保持しておくクラスも別途必要だが、自明なので省略。
この辺りまで書くとテストも通る。
後は、View と Presenter を関連付けるだけ。
public partial class Form2 : Form, IForm2
{
//…略…
private void dataGridView2_CellEndEdit(
object sender, DataGridViewCellEventArgs e)
{
this.presenter.Update(e.RowIndex);
}
public void SetGridStyle(int col, int row, CellStyle styleId)
{
this.dataGridView2[col, row].Style = CellStyleMap.StyleOf(styleId);
}
}
前回と同様、View オブジェクト(Form2)は受身で丸投げなクラスで、余りテストの必要性が高くないほんの少量のコードを残して、その他の振る舞いのコードを Presenter に移した。
こんな風に、一見いかにも GUI の最表層みたいな振る舞いでも、フォーム=View を薄く薄くしていく事で、妥当な網羅性を備えた UnitTest が書けるようになる。
0 件のコメント:
コメントを投稿