アサーションは現実を乗り越えられない
通常、アサーションは実際のデータとの接触を生き延びません。これは、ソフトウェアエンジニアリングプロセスの一部であり、どのデータを処理するか、どのデータを範囲外にするかを決定します。
循環族グラフ
家族の「木」(実際、それはサイクルを含む完全なグラフです)に関して、素晴らしい逸話があります:
私は成長した娘がいる未亡人と結婚しました。よく訪ねてきた父は、継娘に恋をして結婚しました。その結果、父は息子になり、娘は母になりました。しばらくして、私は妻に私の父の兄弟である息子と私の叔父を与えました。父の妻(私の娘であり母でもあります)には息子がいます。その結果、兄弟と孫が同じ人になりました。私の妻は今や私の祖母です。なぜなら彼女は私の母の母親だからです。だから私は妻の夫であり、同時に妻の継孫でもある。つまり、私は自分のおじいちゃんです。
サロゲートまたは「あいまいな父権」を考慮に入れると、事態はさらに奇妙になります。
それに対処する方法
範囲外としてサイクルを定義する
ソフトウェアがそのようなまれなケースを処理しないように決定することができます。このような場合、ユーザーは別の製品を使用する必要があります。これにより、より多くのアサーションとより単純なデータモデルを維持できるため、より一般的なケースへの対応がより堅牢になります。
この場合、必要なときにユーザーが別の製品に簡単に移行できるように、ソフトウェアに適切なインポートおよびエクスポート機能を追加します。
手動の関係を許可する
ユーザーが手動の関係を追加できるようにすることができます。これらの関係は「一流の市民」ではありません。つまり、ソフトウェアはそれらをそのまま受け取り、チェックせず、メインデータモデルで処理しません。
その後、ユーザーはまれなケースを手動で処理できます。データモデルは非常に単純なままであり、アサーションは存続します。
手動の関係には注意してください。それらを完全に構成可能にして、完全に構成可能なデータモデルを作成するという誘惑があります。これは機能しません。ソフトウェアが拡張されず、奇妙なバグが発生し、最終的にユーザーインターフェイスが使用できなくなります。このアンチパターンは「ソフトコーディング」と呼ばれ、「The Daily WTF」にはその例がたくさんあります。
データモデルをより柔軟にし、アサーションをスキップし、不変条件をテストする
最後の手段は、データモデルをより柔軟にすることです。ほとんどすべてのアサーションをスキップし、完全なグラフに基づいてデータモデルを作成する必要があります。上記の例が示すように、自分の祖父になることは簡単にできるので、サイクルを持つことさえできます。
この場合、ソフトウェアを広範囲にテストする必要があります。ほぼすべてのアサーションをスキップする必要があったため、追加のバグが発生する可能性が高くなります。
テストデータジェネレーターを使用して、異常なテストケースをチェックします。Haskell、Erlang、またはC用のクイックチェックライブラリがあります。Java / ScalaにはScalaCheckとNyayaがあります。テストのアイデアの1つは、ランダムな母集団をシミュレートし、ランダムに交配させ、次にソフトウェアで最初にインポートしてから結果をエクスポートすることです。予想は、出力のすべての接続が入力にもあり、その逆も同様です。
プロパティが同じままであるケースは、不変と呼ばれます。この場合、不変量は、シミュレートされた母集団内の個人間の「ロマンチックな関係」のセットです。できるだけ多くの不変量を見つけて、ランダムに生成されたデータでそれらをテストしてください。不変条件は機能することができます、例えば:
- 「ロマンチックな関係」を追加しても、叔父は叔父のままです。
- すべての子供には親がいます
- 2世代の母集団には少なくとも1人の祖父母がいる
または、技術的なこともあります。
- ソフトウェアは、最大100億のメンバーのグラフでクラッシュしません(相互接続の数に関係なく)。
- ソフトウェアはO(ノード数)とO(エッジ数^ 2)でスケーリングします
- ソフトウェアは、最大100億のメンバーまでのすべてのファミリーグラフを保存および再ロードできます
シミュレートされたテストを実行すると、多くの奇妙なコーナーケースが見つかります。それらを修正するには、かなりの時間がかかります。また、多くの最適化が失われ、ソフトウェアの実行速度が大幅に低下します。それが価値があるかどうか、これがソフトウェアの範囲内にあるかどうかを判断する必要があります。