これはまさに私のプロジェクトで起こったことです。今日は、品質を損なうことなくテストケースの数をさらに減らす方法を説明します。
テストオブジェクト
まず、製品について少しお話します。 Tinkoffで、私たちのチームはブロックを開発しました。これらは、実装と構成で構成されるReactコンポーネントです。実装はコンポーネント自体であり、私たちが開発し、ユーザーがブラウザーに表示します。構成は、このオブジェクトのパラメーターとコンテンツを設定するJSONです。
ブロックの主なタスクは、美しく、さまざまなユーザーに同じように見えることです。同時に、ブロックは構成とコンテンツから非常に大幅に変更される可能性があります。
たとえば、ブロックは次のようになります-背景なし、ボタンと右側の画像:
またはこのように-背景あり、ボタンなし、左側の画像あり:
または、一般的に、このように-ボタンの代わりにリンクがあり、テキストにリストがありません:
上記のすべての例は、1つのバージョンの構成(この特定のReactコンポーネントが処理できるJSON構造)を持つ1つの同じブロックですが、内容が異なります。
回路自体:
{
components: {
background: color,
panel: {
panelProps: {
color: {
style: ['outline', 'color', 'shadow', 'custom'],
background: color
},
size: ['s', 'm', 'l'],
imagePosition: ['left', 'right']
},
title: {
text: text,
size: ['s', 'l'],
htmlTag: ['div', 'b', 'strong', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6']
},
description: {
text: html,
htmlTag: ['div', 'b', 'strong', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6']
},
image: {
alt: text,
title: text,
image: {
src: image,
srcset: [{
src: image,
condition: ['2x', '3x']
}],
webpSrcset: [{
src: image,
condition: ['1x', '2x', '3x']
}]
},
imageAlign: ['top', 'center', 'bottom']
},
button: {
active: boolean,
text: text,
color: {
style: ['primary', 'secondary', 'outline', 'outlineDark', 'outlineLight', 'textLink', 'custom'],
backgroundColor: color
},
onClick: {
action: ['goToLink', 'goToBlock', 'showBlock', 'crossSale', 'callFormEvent'],
nofollow: boolean,
url: url,
targetBlank: boolean,
title: text,
noindex: boolean,
guid: guid,
guidList: [{
guid: guid
}],
formId: guid,
crossSaleUrl: url,
eventName: text
},
htmlTag: ['div', 'b', 'strong', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6']
},
href: url
}
}
}
この場合、右の図のブロックの値はになります
components.panel.imagePosition = right。そして、左の写真のブロックにはがありcomponents.panel.imagePosition = leftます。ボタン付きのブロックの場合-components.button.active = trueなど。原則が明確であることを願っています。これは、ブロックのすべてのパラメーターが設定される方法です。
パラメータの組み合わせからのケース
この記事では、ブロックダイアグラムのバージョン管理の問題、コンテンツを入力するためのルール、またはデータの出所については触れません。これらはすべて、一連のテストケースのコンパイルに影響を与えない個別のトピックです。知っておくべき主なこと:コンポーネントに影響を与える多くのパラメーターがあり、それぞれが独自の値のセットを取ることができます。
上記の例では、かなり単純な構成のブロックを選択しました。しかし、それでも、特にブラウザー間の互換性を考慮する必要がある場合は、すべてのパラメーターの値のすべての組み合わせをチェックするのに、許容できないほど長い時間がかかります。通常、ペアワイズテスト、またはペアワイズテストがここで役に立ちます。彼についてはすでにたくさんの記事が書かれており、トレーニングもあります。突然出くわしなかった場合は、必ずお読みください。
適用時に取得するテストケースの数を見積もりましょう。25を超えるパラメーターがあり、そのうちのいくつかは7つおよび9つの値のバリアントを取ります。はい、無視できます。たとえば、レイアウトを確認している場合、ガイドは重要ではありません。ただし、ペアワイズテストを使用すると、80を超えるテストケースを取得できます。そして、これは、私がすでに書いたように、最も複雑なブロックではなく、ブラウザー間の互換性を考慮しないためのものです。現在、150を超えるブロックがあり、その数は増え続けているため、新しいバージョンのテストとリリースの速度を維持したいのであれば、それほど多くのケースを買う余裕はありません。
1つのパラメータからのケース
ペアワイズテスト方法は、ほとんどの欠陥は2つ以下の要因の相互作用によって引き起こされるというステートメントに基づいています。つまり、ほとんどのバグは、パラメータの1つの値、または2つのパラメータの値の組み合わせのいずれかで現れます。このステートメントの2番目の部分を無視することにし、1つのパラメーターをチェックしてもほとんどのバグが見つかると想定しました。
次に、テストのために、各パラメーターの各値を少なくとも1回チェックする必要があることがわかりました。しかし同時に、各ブロックは構成全体を運びます。次に、新しいケースごとに、ケースの数を最小限に抑えるために、まだ検証されていない値の最大値を確認できます。
簡単な例を使用して、ケースを構築するためのアルゴリズムを分析してみましょう。スキームからボタンコンポーネントを取得して、そのテストケースを作成しましょう。
button: {
active: boolean,
text: text,
color: {
style: ['primary', 'secondary', 'outline', 'custom'],
backgroundColor: color
}
例を単純化するために、リストの長さをに減らしました
button.color.style。
手順1.各フィールドのコンテンツオプションを作成する
ここでのすべてはペアワイズテストのようなものです:各フィールドが取ることができる値を理解する必要があります。たとえば
button.active、この場合、値は2つだけです:trueまたはfalse。理論的には、たとえばundefinedキー自体がないなど、より多くのオプションが発生する可能性があります。
ここで、私の意見では、システムの境界と機能を非常に明確に定義し、不要なものをチェックしないことが重要です。つまり、必須キーのチェックまたは値の検証がサードパーティシステムで実装されている場合、この機能はサードパーティシステムでチェックする必要があります。また、ケースとして「正しい」データのみを使用する必要があります。
概して、同じ原理がテストピラミッドで使用されます。必要に応じて、最も重要な統合テストを追加できます。たとえば、到着していないキーの処理を確認できます。しかし、そのようなテストの最小数があるはずです。もう1つのアプローチは、徹底的なテストの追求です。これは、誰もが知っているように、不可能です。
そこで、各フィールドのコンテンツオプションを特定し、次の表を作成しました。
この表には、各パラメーターの各等価クラスが含まれていますが、1回だけです。
これらは、この場合の値クラス、クラスです。
- text_s-短い文字列。
- text_m-長い文字列。
- no_color-色なし;
- rnd_colorは任意の色です。
ステップ2.データでテーブルを充実させる
各ブロックは完全な構成を保持しているため、いくつかの関連データを空白のセルに追加する必要があります。
これで、各列は1つのケースになります。
同時に、不足しているデータを自分で選択するため、優先度に基づいてケースを生成できます。たとえば、ボタンで短いテキストが中程度の長さのテキストよりも頻繁に使用されていることがわかっている場合は、それをより頻繁にチェックする価値があります。
上記の例では、「ドロップされた」ケース、つまり、テーブルに存在しているにもかかわらず、一部のパラメーターがまったくチェックされていないケースにも注意を払うことができます。この場合、
button.color.style: secondary無効化されたボタンのスタイルは関係ないため、外観はチェックされません。
「ドロップされた」ケースがバグにつながるのを防ぐために、結果の値のセットを分析するために使用しました。分析はテストケースの生成中に1回実行され、すべての「ドロップされた」ケースが最終テストケースに手動で追加されました。この問題の解決策はかなり不器用ですが、安価です(もちろん、テスト対象のオブジェクトの構成を変更することはめったにありません)。
より一般的な解決策は、すべての値を2つのグループに分割することです:
- 安全でない値(ケースの「損失」につながる可能性のある値);
- 安全(「脱落」につながることはありません)。
安全でない値はそれぞれ独自のテストケースでチェックされ、安全なデータでケースを充実させることができます。安全な値のために、テーブルは上記の手順に従ってコンパイルされます。
ステップ3.値を明確にする
残っているのは、同等のクラスではなく、具体的な値を生成することだけです。
ここで、各プロジェクトは、テストされたオブジェクトの特性に基づいて、独自の値のバリアントを選択する必要があります。一部の値は非常に簡単に生成できます。たとえば、ほとんどのフィールドで任意の色を使用できます。一部のブロックでは、色をチェックするときにグラデーションを追加する必要がありますが、それは別の同等クラスに移動されます。
テキストの場合はもう少し複雑です。ランダムな文字から文字列を生成する場合、ハイフネーション、リスト、タグ、区切りのないスペースはテストされません。実際のテキストから短行と中行の長さを生成し、必要な文字数にトリミングします。そして、長いテキストで私たちはチェックします:
- htmlタグ(いずれか);
- リンク;
- 番号なしリスト。
この一連のケースは、ブロックの実装に直接起因しています。たとえば、すべてのhtmlタグが一緒に含まれているため、それぞれをテストしても意味がありません。この場合、リンクとリストは別々の視覚処理(ホバーとシュートアウトで強調表示)があるため、別々にチェックされます。
プロジェクトごとに、テストされたオブジェクトの実装に基づいて、独自の実際のコンテンツセットを作成する必要があることがわかりました。
アルゴリズム
もちろん、一見すると、アルゴリズムは複雑で、努力する価値がないように見えるかもしれません。しかし、上記の各段落で説明しようとしたすべての詳細と例外を省略すると、非常に簡単になります。
ステップ1.すべての可能な値をパラメーターテーブルに追加します:
ステップ2.値を空のセルに複製します:
ステップ3.抽象的な値を具体的な値に変換してケースを取得します:
テーブルの各列は1つのケースです。
アプローチの利点
テストケースを生成するこの方法には、いくつかの重要な利点があります。
ケースが少ない
何よりもまず、ペアワイズテストよりもケースが大幅に少なくなります。ボタンを使用した単純化された例をとると、ペアワイズテストでは8ケースではなく4ケースになります。
テスト対象のオブジェクトに含まれるパラメーターが多いほど、ケースの節約が大きくなります。たとえば、記事の冒頭で示した完全なブロックの場合、11のケースがあり、ペアワイズの助けを借りて-260です。
機能がより複雑になっても、ケースの数は増えません
2つ目の利点は、テスト中に考慮される新しいパラメーターが表示された場合、ケースの数が常に増えるとは限らないことです。
たとえば
button.color.textColor、値が同等のクラスno_colorを持つパラメータがボタンに追加されたとしますrnd_color。その後、4つのケースが残り、それぞれに1つのパラメーターが追加されます:
ケースの数は、一部のパラメーターの値がケースよりも多い場合にのみ増加します。
あなたはより頻繁に重要なものをチェックすることができます
値を強化することで(アルゴリズムのステップ2)、優先度の高い値またはリスクの高い値をより頻繁にチェックできます。
たとえば、以前のユーザーがより短いテキストをより頻繁に使用し、現在はより長いテキストを使用していることがわかっている場合、より長いテキストでケースを充実させ、より頻繁に実際のユーザーケースに入ることができます。
自動化可能
上記のアルゴリズムは、自動化に非常に適しています。もちろん、アルゴリズムによって生成されたケースは、人間が生成したケースよりも実際のケースのようには見えません。少なくとも色を一致させ、テキストをトリミングすることによって。
しかし一方で、テスターの参加なしにすでに開発プロセスにある場合は、ケースが表示され、フィードバックループが大幅に減少します。
短所
当然のことながら、このようなケースの生成は特効薬とはほど遠いものであり、欠点があります。
結果の分析の難しさ
ケースを生成する過程で、テストデータが互いに混ざり合っていることに気づいたと思います。このため、ケースが落下すると、落下の原因を特定することがより困難になります。結局のところ、ケースで使用されるパラメータのいくつかは、テスト結果にまったく影響を与えません。
一方では、これによりテスト結果の解析が困難になります。ただし、一方で、テスト対象のオブジェクトに必要なパラメータが大量に必要な場合は、バグの原因を特定することも困難になります。
バグを見逃す可能性があります
記事の最初に戻ります。この方法を使用すると、2つ以上のパラメーターの組み合わせによって引き起こされるバグをスキップできる可能性があります。しかし、私たちはスピードで勝つので、それぞれの特定のプロジェクトにとって何がより重要であるかを決めるのはあなた次第です。
バグを2回見逃さないために、ゼロバグポリシーを導入し、追加のテストケースを使用して、見逃した各バグを閉じ始めました。自動生成されなくなりましたが、手書きで作成されました。これにより、優れた結果が得られました。現在、150を超えるブロック(テスト済みオブジェクト)があり、1日あたり数回のリリースがあり、1か月あたり0から3の重要ではないバグを見逃しています。
結論
テスト対象のオブジェクトにさまざまな入力パラメータがあり、ケースの数を減らしてテストの時間を短縮したい場合は、1つのパラメータを使用してケースを生成する上記の方法を試すことをお勧めします。
私の意見では、これはフロントエンドコンポーネントに最適です。たとえば、スクリーンショットテストで外観を確認する場合など、時間を3倍以上短縮できます。そして、初期段階での症例の出現により、開発はより速く進みます。
もちろん、新しいテスラの自動操縦をテストしている場合は、バグを見逃す可能性がわずかであっても無視することはできません。しかし、ほとんどの場合、現代世界の速度は非常に重要な品質基準であることを忘れないでください。そして、速度の向上は、発見されたいくつかの小さな問題よりも良い結果をもたらします。
そして、最も責任のある人のために、次の記事では、カスタムケースとStoryBookを使用したパラメーターの組み合わせによって引き起こされるトリッキーなバグから自分自身をさらに保護する方法を説明します。