テストが知らないこと
deleteの後にgetを書く。書いていて、これ要るかと思う。
二度尋ねる
$repo->delete($id);
$this->assertNull($repo->get($id));
saveの後にfind。updateの後にget。書いた本人も、なぜ二度目が要るのか説明できない。
「念のため」と言います。「確認のため」と言います。
voidの沈黙
delete($id): void. 削除した。何件消えたかは言わない。
SQLは知っています。affected_rows = 1。けれど戻り値がvoidである限り、その数は関数の中で生まれて消えます。
外にいるテストは、内側で何が起きたかを知る術を持ちません。だから別の証人を呼ぶ。getに「無い」と答えさせる。
間接証拠です。直接証拠ではない。
観察者は外にいる
テストは外から見ます。観察者です。
観察者には選択肢が二つあります。
- 内部の手応えを取り出して見えるようにする——カプセル化を壊す
- 別の方法で確かめる——テストが二重になる
TDDが小さく抱えてきた矛盾。テストが外にいる限り、内で起きたことは伝聞でしか書けない。
内側に証拠を持つ
Be Frameworkでは、削除は変容の一段になります。
#[Be([ArticleDeleted::class])]
final readonly class ArticleDeleteRequest
{
public function __construct(
#[Input] public string $id,
) {}
}
final readonly class ArticleDeleted
{
public function __construct(
#[Input] string $id,
#[Inject] ArticleRepository $repo,
) {
$affectedRows = $repo->delete($id);
$this->been->with(new DeletedContext(id: $id, affectedRows: $affectedRows->count));
}
}
Ray.MediaQueryはインターフェースの戻り値をintにするだけで、affected_rowsを直接届けます。
外には晒しません。中で、affectedRows: 1という事実を$beenに書き留める。
$result = $becoming(new ArticleDeleteRequest($id));
$this->assertInstanceOf(ArticleDeleted::class, $result);
$this->assertSame(1, $result->been->last()->affectedRows);
getは呼びません。オブジェクト自身が、自分がArticleDeletedである根拠を持っている。
記録ではなく条件
ログは普通、起きたことを後から書き留めます。
$beenは違います。証跡がなければArticleDeletedは成立しない。affectedRows: 1は事後の記録ではなく、存在の条件です。
外から見るかぎり、二度尋ねるしかない。