TDDを読み取り/書き込み機能に適用するにはどうすればよいですか?


10

鶏と卵の問題のようです。

何らかのデータストアに書き込み関数を書き込むことはできますが、テスト済みの読み取り関数がなければ適切に保存したことを知ることはできません。

読み取り関数をデータストアから読み取ることができますが、テストされた書き込み関数なしで、データストアにデータを読み込むにはどうすればよいですか?

編集:

SQLデータベースに接続してトランザクションを作成し、使用するオブジェクトを保存およびロードしています。DBが提供するアクセス関数をテストする意味はありませんが、このようなDB関数をラップしてオブジェクトをシリアル化/逆シリアル化します。DBとの間で適切なものを正しく読み書きしていることを確認したいと思います。

@snowmanが言及しているように、追加/削除とは異なります。私が書いた内容が正しいことを知りたいのですが、それには十分にテストされた読み取り機能が必要です。読んだときに、書いたものと同等のオブジェクトが正しく読まれたことを確認したい。ただし、十分にテストされた書き込み関数が必要です。


独自のデータストアを作成していますか、それとも既存のデータストアを使用していますか?既存のものを使用している場合は、すでに機能していると想定してください。独自に作成している場合、これはTDDを使用して他のソフトウェアを作成するのと同じように機能します。
ロバートハーベイ


1
密接に関連していますが、これはその特定の質問の複製ではないと思います。だまされたターゲットは追加/削除について話している、これは読み取り/書き込みです。違いは、読み取り/書き込みの依存性は、読み取り/書き込み中のオブジェクトの内容に依存する可能性が高いのに対し、単純な追加/削除テストは、オブジェクトが存在するかどうかにかかわらず、はるかに単純になる可能性が高いことです。

2
読み取り機能をテストするために、データがあり書き込み機能がないデータベースをステージングできます。
-JeffO

回答:


7

読み取り機能から始めます。

  • テストセットアップで:データベースを作成し、テストデータを追加します。移行スクリプトまたはバックアップから。これはあなたのコードではないので、TDDでのテストは必要ありません

  • テスト:リポジトリをインスタンス化し、テストデータベースをポイントして、Readメソッドを呼び出します。テストデータが返されることを確認します。

これで完全にテストされた読み取り関数ができたので、既存の読み取りを使用して独自の結果を検証できる書き込み関数に移動できます。


メモリ内にDBを作成して速度を上げることはできますが、それは複雑すぎるかもしれません。単体テストで代わりにモックを使用してみませんか?
BЈовић

1
ここでは少し悪魔の擁護者ですが、データベースが正しく作成されたことをどのようにテストしますか?OPが述べたように、鶏と卵。
user949300

1
@Ewan-DBコードをテストしないでください。しかし DBセットアップコードがどこかでINSERTを忘れたり、列に間違った値を入れたりしなかったことをどうやって知るのでしょうか?
user949300

1
純粋なTDDアプローチからは、テストが要件です。論理的に間違ってはいけません。現実の世界で目を光らせなければならない
ユアン

1
Quis custodiet ipsos custodes?または、「誰がテストをテストしますか?」:-)純粋なTDDの世界では、これは恐ろしく退屈でバグが発生しやすい(特に、8つのJOINSを持つ複雑な複数のテーブル構造である場合)方法になります。賛成。
-user949300

6

私はしばしば、書き込みに続いて読み取りを行います。例(擬似コード)

Foo foo1 = setup some object to write
File tempfile = create a tempfile, possibly in memory 
writeFoo(foo1, tempfile) 
Foo foo2 = readFoo(tempfile) 
assertEquals(foo1, foo2); 
clean-up goes here

後で追加

このソリューションが「実用的」かつ「十分」であることに加えて、他のソリューションが間違ったことをテストしていると主張することができます。文字列またはSQLステートメントが一致するかどうかをテストするのはひどい考えではありません。自分でやったのですが、副作用をテストしているため、脆弱です。大文字の変更、フィールドの追加、またはデータ内のバージョン番号の更新を行うとどうなりますか?効率のためにSQLドライバーが呼び出しの順序を切り替えたり、更新されたXMLシリアライザーが余分なスペースを追加したり、スキーマバージョンを変更したりするとどうなりますか?

公式の仕様を非常に厳守する必要がある場合、詳細を確認することが適切であることに同意します。


1
それは90%の本当に濃い擬似コードだから?わからない。テキストを強調表示して、コードのノイズを少なくするのでしょうか?
ラバーダック

1
はい@ユアン。熱狂者はこれに眉をひそめますが、実用的なプログラマーは「十分に良い」と言って先に進みます。
ラバーダック

1
私は質問を次のように読みます。「熱狂者のようにTDDに従うと仮定して...」
Ewan

1
OPとTDDの私の解釈では、テストは最初に記述し、他の場所でもテストしない限り、読み取りと書き込みの両方を使用しないでください。
ユアン

2
あなたはしかし、要件はと「DBにデータを書き込む必要があり、書き込み」「DBからデータを返す必要があります読んで」ある「読み取りは、私が書いたものを返す必要があります」、テストしている
ユアン・

4

しないでください。I / Oを単体テストしないでください。時間の無駄です。

ユニットテストロジック。I / Oコードでテストしたいロジックがたくさんある場合は、コードをリファクタリングして、I / Oの実行方法とI / Oの実際のビジネスからI / Oを実行するロジックを分離する必要があります。 (テストすることはほぼ不可能です)。

少し詳しく説明すると、HTTPサーバーをテストする場合は、統合テストと単体テストの2種類のテストを実行する必要があります。ユニットテストは、I / Oとまったく対話しないようにします。それは時間がかかり、コードの正確性とは関係のない多くのエラー状態をもたらします。ユニットテストはネットワークの状態に左右されるべきではありません!

コードは分離する必要があります:

  • どの情報を送信するかを決定するロジック
  • 情報の特定のビットを送信するために送信するバイトを決定するロジック(応答などを生のバイトにエンコードする方法)
  • これらのバイトを実際にソケットに書き込むメカニズム。

最初の2つは論理と決定に関係し、ユニットテストが必要です。最後のステップでは、意思決定が行われても多くは行われず、統合テストを使用して見事にテストできます。

これは実際には一般的には良い設計ですが、その理由の1つはテストを容易にすることです。


ここではいくつかの例を示します。

  • リレーショナルデータベースからデータを取得するコードを記述している場合、リレーショナルクエリから返されたデータをアプリケーションモデルにマッピングする方法を単体テストできます。
  • リレーショナルデータベースにデータを書き込むコードを記述している場合、使用する特定のSQLクエリを実際にテストすることなく、データベースに書き込むデータを単体テストできます。たとえば、アプリケーションの状態の2つのコピーをメモリに保持できます。データベースの外観を表すコピーと作業コピーです。データベースと同期したい場合は、これらを比較し、その差分をデータベースに書き込む必要があります。その差分コードを非常に簡単に単体テストできます。
  • 構成ファイルから何かを読み取るコードを記述している場合、構成ファイル形式パーサーをテストしますが、ディスクから取得した文字列ではなく、テストソースファイルの文字列を使用します。

2

これが標準的な慣行であるかどうかはわかりませんが、私にとってはうまくいきます。

私の非データベース読み取り書き込み方式の実装では、私は自分の型固有の使用toString()およびfromString()実装の詳細などのメソッドを。

これらは、単独で簡単にテストできます。

 assertEquals("<xml><car type='porsche'>....", new Car("porsche").toString());

実際の読み書き方法については、1つのテストで物理的に読み書きする1つの統合テストがあります

ちなみに、読み取り/書き込みを一緒にテストするテストが1つあるだけで問題はありますか?


気分が良くない、または「純粋」ではないかもしれませんが、これは実用的な解決策です。
ラバーダック

私も一緒に読み書きをテストするというアイデアが好きです。toString()は実用的な妥協案です。
user949300

1

既知のデータは、既知の方法でフォーマットする必要があります。これを実装する最も簡単な方法は、@ k3bで説明したように、定数文字列を使用して結果を比較することです。

ただし、定数に限定されません。書き込まれたデータには、正規表現やデータの機能を探すアドホックプローブなど、さまざまな種類のパーサーを使用して抽出できるプロパティがいくつかあります。

データの読み取りまたは書き込みに関しては、システムの他の部分からの干渉の可能性なしにテストを実行できるインメモリファイルシステムがあると便利です。適切なメモリ内ファイルシステムにアクセスできない場合は、一時ディレクトリツリーを使用します。


1

依存関係の注入とモックを使用します。

SQLドライバーをテストしたくないし、SQLデータベースがオンラインで適切にセットアップされているかどうかもテストしたくない場合。これは、統合テストまたはシステムテストの一部になります。コードが送信するはずのSQLステートメントを送信するかどうか、および応答を想定どおりに解釈するかどうかをテストする必要があります。

したがって、データベースで何かを行うことになっているメソッド/クラスがある場合、それ自体でデータベース接続を取得しないでください。データベース接続を表すオブジェクトが渡されるように変更します。

実動コードで、実際のデータベースオブジェクトを渡します。

単体テストでは、実際のデータベースが実際にデータベースサーバーに接続しないように動作する模擬オブジェクトを渡します。受信するはずのSQLステートメントを受信し、ハードコードされた応答で応答するかどうかを確認するだけです。

このようにして、実際のデータベースを必要とせずにデータベース抽象化レイヤーをテストできます。


悪魔の擁護者:どのSQLステートメントが「受け取ることになっている」かをどのようにして知るのですか?DBドライバーがコードに表示される順序を最適化するとどうなりますか?
user949300

@ user949300通常、データベースモックオブジェクトはデータベースドライバーを置き換えます。
フィリップ

リポジトリをテストしているときは、模擬データベースクライアントを注入しても意味がありません。データベースで動作するsqlがコードで実行されることをテストする必要があります。そうでない場合はあなたは自分のモックテストUO終了
ユアン・

@Ewan単体テストの目的ではありません。単体テストは、他の世界から隔離された1つのコード単位をテストします。コードやデータベースなどのコンポーネント間の相互作用はテストしていません。それが統合テストの目的です。
フィリップ

はい。DBリポジトリを単体テストするポイントはないと言っています。統合テストはやって唯一の価値がある
ユアン・

0

オブジェクトリレーショナルマッパーを使用している場合、通常、関連付けられたライブラリを使用して、集計を作成し、それを永続化し、新しいセッションから再ロードしてマッピングが正しく機能することをテストできます。元のオブジェクト。

NHibernateはPersistence Specification Testingを提供しています。高速の単体テストのために、メモリ内のストアに対して機能するように構成できます。

リポジトリと作業単位のパターンの最も単純なバージョンに従い、すべてのマッピングをテストすると、ほとんど機能していることが期待できます。

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