TDDの最初のテストで大丈夫だと思うオブジェクトを作成しています


15

私はTDDにかなり慣れていないので、実装コードの前に来る最初のテストを作成するときに問題があります。実装コードにフレームワークがなければ、私は最初のテストを自由に書くことができますが、Java / OOの問題に対する考え方によって常に汚染されているようです。

たとえば、私のGithub ConwaysGameOfLifeExampleで最初に書いたテスト(rule1_zeroNeighbours)では、まだ実装されていないGameOfLifeオブジェクトを作成することから始めました。存在しないsetメソッド、存在しないstepメソッド、存在しないgetメソッドを呼び出し、アサートを使用しました。

テストはさらにテストを書いてリファクタリングするにつれて進化しましたが、元々は次のようなものでした:

@Test
public void rule1_zeroNeighbours()
{
    GameOfLife gameOfLife = new GameOfLife();
    gameOfLife.set(1, 1, true);
    gameOfLife.step();
    assertEquals(false, gameOfLife.get(1, 1));
}

この最初のテストを書くためにこの初期段階でどのように決定したかに基づいて実装の設計を強制していたので、これは奇妙に感じました。

あなたがTDDを理解する方法でこれは大丈夫ですか?私はテストと実装がリファクタリングによって時間とともに進化したという点でTDD / XPの原則に従っているようです。この方法で開始することにより、ソリューション。

TDDは他にどのように使用されますか?GameOfLifeオブジェクトなしで、プリミティブと静的メソッドのみで開始することにより、リファクタリングの反復をさらに行うことができましたが、それはあまりにも不自然に思えます。


5
TDDは、慎重な計画や慎重な設計パターン選択の代わりにはなりません。ただし、テストの最初の数行を満たす実装を作成する前は、依存関係を作成してから、計画が愚かであること、間違ったパターンを選択したこと、または単にテストが要求する方法でクラスを呼び出すのは厄介または混乱することです。
svidgen

回答:


9

この最初のテストを書くためにこの初期段階でどのように決定したかに基づいて実装の設計を強制していたので、これは奇妙に感じました。

これがあなたの質問のキーポイントだと思います。これが望ましいかどうかは、事前に設計する必要があるコードニンジャのアイデアに傾いているかどうかに依存し、TDDを使用して実装を埋めるか、またはテストに関与する必要があるというdurronのアイデアに依存します設計だけでなく実装も推進します。

これらのうちどれを好むか(またはあなたが真ん中に落ちるか)は、好みとして自分で発見する必要があるものだと思います。各アプローチの長所と短所を理解しておくと役立ちます。おそらくたくさんありますが、主なものは次のとおりです。

Pro Upfrontデザイン

  • TDDが優れたプロセスで設計を駆動しても、それは完全ではありません。具体的な目的地を念頭に置いていないTDingは行き止まりに陥ることがありますが、少なくともこれらの行き止まりのいくつかは、最終的にどこに行きたいかについて少し前もって考えることで回避できたかもしれません。このブログ記事では、ローマ数字カタの例を使用してこの議論を行っており、それを示すためのかなり良い最終実装をしています。

プロテスト駆動設計

  • コードのクライアント(テスト)を中心に実装を構築することにより、不要なテストケースの作成を開始しない限り、YAGNI準拠をほぼ無料で取得できます。より一般的には、消費者による使用を中心に設計されたAPIを取得します。

  • コードを記述する前にUMLダイアグラムの束を描画し、ギャップを埋めるというアイデアは素晴らしいですが、現実的ではありません。Steve McConnellのCode Completeでは、設計は「邪悪な問題」として有名です。最初に少なくとも部分的に解決しないと完全に理解できない問題です。これを、要件の変化によって根本的な問題自体が変わる可能性があるという事実と組み合わせると、この設計モデルは少し希望が持てなくなってきます。テストドライビングを使用すると、実装だけでなく、デザインで一度に1つの作業の塊を食い止めることができ、少なくとも赤から緑に変わるまでは、そのタスクが最新で関連性があることを知ることができます。

あなたの特定の例については、durronが言うように、最も簡単なテストを書いて、できる限り最小限のインターフェースを使用して設計を追い出すアプローチを行った場合、おそらくコードスニペットのものよりもシンプルなインターフェースから始めるでしょう。


このリンクは非常に優れたBenでした。それを共有してくれてありがとう。
ラバーダック

1
@RubberDuckどういたしまして!実際、私は完全に同意していませんが、その観点を議論するのに優れた仕事をしていると思います。
ベンアーロンソン

1
私はどちらをするのか分かりませんが、それはそのケースをうまく作ります。正しい答えは中間のどこかにあると思います。計画を立てる必要がありますが、確かにテストが厄介だと感じたら、再設計してください。とにかく... ++良い古い豆を表示します。
ラバーダック

17

最初にテストを作成するには、実装するAPI設計する必要があります。オブジェクト全体 を作成するテストを作成し、GameOfLifeそれを使用してテストを実装することで、すでに間違った方向から始めています。

JUnitとMockitoを使用した実用的な単体テストから

最初は、そこにさえない何かを書くのに気まずいかもしれません。コーディングの習慣を少し変更する必要がありますが、しばらくすると、すばらしいデザインの機会になるでしょう。最初にテストを作成することにより、クライアントが使用するのに便利なAPIを作成できる可能性があります。テストは、新しく生まれたAPIの最初のクライアントです。これがTDDの本当の目的です。APIの設計です。

テストでは、APIを設計することはあまり試みません。すべての機能が外部GameOfLifeクラスに含まれるステートフルシステムをセットアップしました。

このアプリケーションを作成する場合は、代わりに、作成したい部分について考えます。たとえばCell、大規模なアプリケーションに進む前に、クラスを作成し、そのためのテストを作成します。確かに、Conwayを適切に実装するために必要な「あらゆる方向に無限」データ構造のクラスを作成し、それをテストします。すべてが完了したら、mainメソッドなどを含むクラス全体を書くことを考えます。

「失敗するテストを書く」ステップについて簡単に説明します。しかし、あなたが望むように機能する失敗したテスト書くことはTDDの中核です。


1
Cellがのラッパーに過ぎないことを考慮するとbooleanその設計は確かにパフォーマンスが低下します。将来的に3つ以上の状態を持つ他のセルオートマトンに拡張可能にする必要がない限り、
user253751

2
@immibisそれは細部をめぐって混乱しています。セルのコレクションを表すクラスから始めることができます。また、後でパフォーマンスが問題になる場合は、セルクラスとそのテストをセルのコレクションを表すクラスに移行/マージすることもできます。
エリック

@immibisパフォーマンス上の理由から、ライブネイバーの数を保存できます。着色の理由で、セルが生きていたダニの数
。– Blorgbeard

@immibisの早すぎる最適化は悪です...さらに、原始的な強迫観念を回避することは、サポートする状態の数に関係なく、高品質のコードを記述するための優れた方法です。ご覧
ポール

0

これについてさまざまな考え方があります。

コンパイルしないテストはエラーです-利用可能な最小の量産コードを書き直してください。

Some Say:antを吸う(または吸わない)かどうかを最初にテストしてから、欠落しているクラス/メソッドを作成してもかまいません

最初のアプローチでは、実際には赤緑のリファクタリングサイクルにあります。第二に、達成したいことの概要が少し広くなります。

どちらの方法で作業するかはあなた次第です。私見は両方のアプローチが有効です。


0

「一緒にハックする」方法で何かを実装する場合でも、プログラム全体に関係するクラスと手順を考えます。あなたはこれを熟考し、これらの設計思想を最初にテストとして書き留めました-それは素晴らしいことです!

両方の実装を繰り返してこの初期テストを実行し、さらにテストを追加して設計を改善および拡張します。

役立つのは、Cucumberなどを使用してテストを書き込むことです。


0

テストの作成を開始する前に、システムの設計方法を検討する必要があります。設計段階でかなりの時間を費やす必要があります。行った場合、TDDでこのような混乱は生じません。

TDDは単なる開発アプローチリンクです。TDD1
.テストを追加します
2.すべてのテストを実行して、新しいテストが失敗するかどうかを確認します
3.コードを記述します
4.テストを実行します
5.コードをリファクタリングします
6.繰り返します

TDDは、ソフトウェアの開発を開始する前に計画していたすべての必要な機能をカバーするのに役立ちます。リンク:利点


0

そのため、JavaまたはC#で記述されたシステムレベルのテストは好きではありません。c#のSpecFlowまたはJavaのCucumberベースのテストフレームワーク(JBehaveの場合があります)をご覧ください。その後、テストは次のようになります。

ここに画像の説明を入力してください

また、すべてのシステムテストを変更することなく、オブジェクトのデザインを変更できます。

(「通常の」単体テストは、単一のクラスをテストする場合に最適です。)

Java用のBDDフレームワークの違いは何ですか?

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.