34

組み込みハードウェアの一部のデバイス ドライバーの単体テストを作成する必要がある状況があります。コードはかなり古くて大きく、残念ながら多くのテストがありません。現時点で可能なテストは、OS を完全にコンパイルしてデバイスにロードし、実際のシナリオで使用して「動作する」ことを確認することだけです。個々のコンポーネントをテストする方法はありません。

ここで、組み込みデバイスの単体テストについて議論している素敵なスレッドに出くわしました。そこから多くの情報を取得しました。もう少し具体的に言って、そのようなシナリオでデバイス ドライバーをテストするための「ベスト プラクティス」があるかどうか尋ねたいと思います。問題のボードが通信しているデバイスをシミュレートできるとは思わないので、おそらく実際のハードウェア自体でテストする必要があります。

これを行うことで、ドライバーの単体テスト カバレッジ データを取得し、開発者がテストを作成してドライバーのカバレッジを向上させることができるようになることを願っています。

私が思いつくのは、OS 上で動作する組み込みアプリケーションを作成し、ドライバー コードを実行してから、結果をテスト ハーネスに送り返すことです。このデバイスには、コードを実行できるように、おそらくテスト PC からアプリケーションを駆動するために使用できるインターフェイスがいくつかあります。

他の提案や洞察は非常に高く評価されます。


更新: 正確な用語ではないかもしれませんが、単体テストと言うときは、OS + ドライバー全体をコンパイルしてデバイスにロードすることなく、コードをテスト/実行できることを意味していました。もしそうしなければならないとしたら、私はそれを統合/システムテストと呼んでいます。

問題は、私たちが持っているハードウェアが限られており、開発者がバグの修正などに使用することが多いことです。1 つを専用にして、CI サーバーと自動テストが行​​われるマシンに接続したままにしておくことは、まったく問題ないかもしれません。この段階。そのため、実際にすべてをビルドしてデバイスにアップロードすることなく、ドライバーをテストする方法を探しています。


概要

以下の優れた回答に基づいて、問題に取り組む合理的な方法は、IOCTL を使用してドライバー機能を公開し、組み込みデバイスのアプリケーション空間にテストを記述して、実際にドライバー コードを実行することだと思います。

また、シリアルまたは USB 経由でドライバーを実行できる API を公開するデバイスのアプリケーション スペースに小さなプログラムを配置することも理にかなっています。ハードウェアとテストを実行します。

プロジェクトが開始されたばかりであれば、テストをほとんど PC レベルで実行できるように、コンポーネントを分離する方法をより細かく制御できると思います。コーディングはすでに完了しており、テスト ハーネスとケースをシステムに後付けしようとしているという事実を考えると、上記のアプローチがより実用的だと思います。

回答ありがとうございます。

4

6 に答える 6

9

昔は、それがデバイス ドライバーのテストとデバッグの方法でした。このようなシステムをデバッグする最良の方法は、エンジニアが組み込みシステムを開発システムとして使用し、システムが十分に成熟したら、元のクロス開発システムを取り除くことでした。

あなたの状況では、いくつかのアプローチが思い浮かびます。

  • ioctl ハンドラーを追加します。各コードは特定の単体テストを実行します
  • 条件付きコンパイルを使用して、ドライバーで機能単体テストを実行し、結果を に出力する main() をドライバーに追加しstdoutます。
  • 最初のデバッグを容易にするために、これをマルチプラットフォームで操作できるようにして、ターゲット ハードウェアでデバッグする必要がないようにすることができます。
  • おそらく、条件付きコードもループバック スタイルのデバイスをエミュレートできます。
于 2009-12-24T08:05:15.243 に答える
7

実際にハードウェアに依存しているコード (レイヤード アーキテクチャのドライバー スタックの最下位レベル) は、ハードウェアまたはハードウェアの高品質なシミュレーション以外ではテストできません。

ハードウェアに直接依存しない高レベル機能のコンポーネント (特定の形式でハードウェアにメッセージを送信するためのプロトコル ハンドラーなど) がドライバーに含まれており、その部分がコード内で適切に自己完結している場合、 PC ベースの単体テスト フレームワークで個別に単体テストを行うことができます。

最低レベルに戻ります。ハードウェアに依存している場合、テスト ジグにハードウェアを含める必要があります。ハードウェア、ドライバ、およびいくつかのテスト ソフトウェアを含むテスト治具を作成できます。主なことは、通常の製品のアプリケーション コードをテストから除外し、代わりに何らかのテスト コードを挿入することだと思います。テスト コードは、ドライバーのすべての機能と特殊なケースを体系的にテストでき (アプリケーション コードはテストしない場合があります)、短時間でドライバーを集中的にテストすることもできます (アプリケーションはおそらくテストしません)。したがって、アプリケーションを実行するだけでなく、限られたハードウェアをより効率的に使用して、より良い結果を得ることができます。

PC をループに入れることができれば、PC がテストに役立つ可能性があります。たとえば、組み込みデバイス用のシリアル ポート ドライバーを作成している場合は、次のようにすることができます。

  • さまざまな既知のデータ ストリームを送信する組み込みデバイスのテスト コードを記述します。
  • PC のシリアル ポートに接続し、送信されたデータ ストリームを検証するテスト コードを実行します。
  • 逆方向も同様です。PC はデータを送信します。組み込みデバイスはそれを受信して​​検証し、PC にエラーを通知します。
  • テストでは、データをフル スピードでストリーミングし、さまざまなバイト タイミングで再生できます (以前、マイクロコントローラーの UART シリコン バグが見つかりました。これは、バイトがバイト間で 5 ミリ秒の遅延で送信された場合にのみ発生します)。

イーサネット ドライバー、Wi-Fi ドライバーでも同様のことができます。

EEPROM やフラッシュ チップなどのストレージ デバイス ドライバーをテストしている場合、PC は同じようには関与できません。その場合、テスト ハーネスはあらゆる種類の書き込み条件 (シングルバイト、ブロックなど) をテストし、あらゆる種類の読み取り条件を使用してデータの整合性を検証できます。

于 2009-12-24T23:54:23.713 に答える
3

私も2、3年前に同じような悩みを抱えていました。デバイス ドライバーを VxWorks から Integrity に移植しました。ドライバーのオペレーティング システムに依存する部分のみを変更しましたが、これはセーフティ クリティカルなプロジェクトであったため、すべての単体テスト、統合テストがやり直されました。単体テストには、LDRA テストベッドと呼ばれる自動テスト ツールを使用しました。単体テストの 99% は、Microsoft コンパイラを搭載した Windows マシンで行われています。今回はその方法を説明します

まず第一に、単体テストを行っているときは、ソフトウェアをテストしています。テストに実際のデバイスを含めると、デバイスもテストされます。ハードウェアまたはハードウェアのドキュメントに問題がある場合があります。ソフトウェアを設計する際に、各機能の振る舞いを明確に記述しておけば、単体テストを非常に簡単に行うことができます。

readMessageTime(int messageNo, int* time); 
//This function calculates the message location, if the location is valid, 
//it reads    the time information 
address=calculateMessageAddr(messageNo); 
if(address!=NULL) { 
    read(address+TIME_OFFSET,time); 
    return success; 
} 
else { 
return failure; 
} 

ここでは、readMessageTime が本来の動作を行っているかどうかをテストしているだけです。calculateMessageAddr が正しい結果を計算しているかどうか、または read が正しいアドレスを読み取っているかどうかをテストする必要はありません。それは他のいくつかの単体テストの責任です。したがって、あなたがしなければならないことは、calculateMessageAddrとread(OS関数)のスタブを書き、正しいパラメータで関数を呼び出すかどうかを確認することです. これは、ドライバーから直接メモリにアクセスしていない場合に当てはまります。この考え方で、OS やデバイスがなくても、あらゆる種類のドライバー コードをテストできます。

デバイス メモリをメモリ空間に直接マップし、デバイス ドライバがデバイス メモリを独自のメモリとして読み書きする場合、少し複雑になります。自動テスト ツールを使用して、ポインターの値を監視し、これらのポインターの値に従って合格/不合格の基準を定義する必要があります。メモリから値を読み取る場合は、期待値を定義する必要があります。これは場合によっては難しいかもしれません。

もう 1 つの問題もあります。開発者は、次のようなドライバーの単体テストで常に混乱します。

 readMessageTime(int messageNo, int* time); 
 //This function calculates the message location, if the location is valid,
 //it does some jobs to make the device ready to read then 
 //it reads the time information 
 address=calculateMessageAddr(messageNo); 
 if(address!=NULL) { 
      do_smoething(); // Get the device ready to read!    
      do_something_else() // do some other stuff so you can read the result in 3us.
      status=NOT_READY;
      while(status==NOT_READY) // mustn't be longer than 3us.
           status=read(address+TIME_OFFSET,time); 
      return success; 
  } else 
  { 
  return failure; 
  } 

ここで do_something と do_something_else は、デバイス上でいくつかのジョブを実行して、デバイスを読み取れるようにします。開発者は常に、「デバイスの準備が永遠に整わず、コードにデッドロックが発生した場合はどうなるか」と自問し、デバイスでこの種のものをテストする傾向があります。

まあ、デバイスの製造元と技術的な作成者を信頼する必要があります。デバイスが 1 ~ 2us で準備が整うと彼らが言っている場合、これについて心配する必要はありません。コードがここで失敗した場合は、デバイスの製造元に報告する必要があります。この問題を克服するための回避策を見つけるのはあなたの仕事ではありません。私の要点がわかりましたか?

これが役立つことを願っています…。

于 2009-12-26T16:50:11.777 に答える
3

私はちょうど2か月前にこの正確な仕事をしました。

推測させてください: おそらく、デバイスに低レベルの詳細を伝えるコードの「スニペット」があります。これらのスニペットが機能することはわかっていますが、デバイス ドライバーに依存しているため、それらをカバーすることはできません。

同様に、すべての行を個別にテストしても意味がありません。それらが単独で実行されることは決してなく、単体テストは製品コードの鏡面反射のように見えることになります。たとえば、デバイスを起動する場合は、接続を作成し、特定の低レベルのリセット コマンドを渡し、次に初期化パラメータ構造体などを渡す必要があります。また、構成の一部を追加する必要がある場合は、これが必要になる場合があります。オフラインにするには、構成を追加してからオンラインにします。そのようなもの。

低レベルのものをテストしたくありません。単体テストは、何も確認せずにデバイスが動作すると想定する方法のみを反映します。

ここで重要なのは、コントローラー、抽象化、およびその抽象化のアダプター実装という 3 つの項目を作成することです。Cpp、Java、または C# では、この抽象化を表す基本クラスまたはインターフェイスを作成します。インターフェイスを作成したと仮定します。スニペットをアトミック操作に分割します。たとえば、インターフェイスで「start」と「add(パラメーター)」というメソッドを作成します。スニペットをデバイス アダプターに配置します。コントローラーは、インターフェースを介してアダプターに作用します。

アダプターに配置したスニペット内のロジックを識別します。次に、このロジックが低レベル (プロトコル処理の詳細など) であるか、コントローラーに属するロジックであるかを判断する必要があります。

その後、次の 2 つの段階でテストできます。 * 具体的なアダプターで動作する単純なテスト パネル アプリケーションを作成します。これは、アダプタが実際に動作することを確認するために使用されます。「start」を押すと起動すること。たとえば、「go offline」、「transmit(192)」、「go online」を順番に押すと、デバイスが期待どおりに応答すること。これが統合テストです。

アダプターの詳細を単体テストしません。唯一の成功基準はデバイスの応答方法であるため、手動でテストします。

ただし、コントローラーは完全に単体テスト済みです。テストコードでモックアウトされている抽象化への依存のみがあります。したがって、具体的なアダプターが含まれていないため、コードはデバイスドライバーに依存しません。

次に、単体テストを記述して、たとえば、メソッド「Add(1)」が実際にモックアウトされた抽象化で「オフラインにする」、次に「Transmit(1)」、「オンラインにする」を呼び出すことを確認します。

ここでの課題は、アダプターとコントローラーを区別することです。何がどこに行くの?私にとってうまくいったのは、最初に前述のテストパネルを作成してから、それを介してデバイスを操作することでした.

アダプターは、デバイスが変更された場合にのみ変更する必要がある詳細を非表示にする必要があります。

  1. 何度も繰り返す必要がある多くのシーケンスでコントロール パネルを操作するのが面倒な場合、またはパネルを操作するために非常にデバイス固有の知識が必要な場合は、粒度が高すぎるため、それらの一部をまとめて一括する必要があります。テストパネルは理にかなっている必要があります。

  2. エンド ユーザーの要件の変更がアダプター コードに影響を与える場合は、粒度が低すぎる可能性があり、操作を分割して、コントローラー クラスのテスト駆動型開発で要件の変更に対応できるようにする必要があります。

于 2010-01-07T18:37:56.913 に答える
2

アプリケーションベースのテストにお勧めします。足場を構築するのは困難で費用がかかる場合でも、ここには多くのメリットがあります。

  • 1 つのシステムではなく、プロセスを 1 回だけクラッシュさせる
  • 標準ツール セット (デバッガー、メモリ チェッカーなど) を使用する機能
  • ハードウェアの可用性の制限を克服する
  • フィードバックの高速化: デバイスにインストールせず、コンパイルしてテストするだけ
  • ...

ネーミングに関する限り、これはコンポーネントのテストと呼ぶことができます。

アプリケーションは、ターゲット OS と同じ方法でデバイス ドライバーを初期化するか、ドライバーのインターンを直接使用することができます。前者はより高価ですが、より多くのカバレッジにつながります. 次に、リンカは不足している関数を通知し、それらをスタブします。おそらく爆発スタブを使用します。

于 2009-12-24T13:24:12.683 に答える
1

単語

問題のボードが通信しているデバイスをシミュレートできるとは思わないので、おそらく実際のハードウェア自体でテストする必要があります。

次に、単体テストから抜け出します。代わりにこれらの表現のいずれかを使用できますか?

  • 自動テスト : テストはユーザーの入力なしで行われます (手動テストの逆)。
  • 統合テスト : 複数のコンポーネントを一緒にテストします (単体テストの反対)
    より大規模に、いくつかのコンポーネントだけでなくシステム全体をテストする場合、それはシステムテストと呼ばれます。

質問のコメントと更新の後に追加:

  • コンポーネント テスト: 統合テストやシステム テストと同様ですが、さらに小規模なテストです。
    注 : 3 つのコンポーネント統合システム テストはすべて、同じ問題セットを異なるスケールで共有しています。それどころか、単体テストはそうではありません (下を参照)。

「実際の」単体テストの利点

統合 (またはシステムまたはコンポーネント) テストでは、テスト カバレッジなどのフィードバックを得ることは確かに興味深いことです。するのは確かに便利です。

しかし、ある時点を超えて進歩するのは非常に難しい (「非常にコストがかかる」と読む) ため、
実際の Unit Tests を追加するなど、補完的なアプローチを使用することをお勧めします。なんで?:

  • エッジまたはエラー条件をシミュレートするのは非常に困難です。(例: トランザクション中にコンピュータの時計が 1 日または 1 年を超える、ネットワーク ケーブルが抜かれている、一部のコンポーネントまたはシステム全体で電源が​​落ちてから上がった、ディスクがいっぱいである)。単体テストを使用すると、これらの条件を再現しようとするのではなくシミュレートするため、はるかに簡単になります。単体テストは、本当に優れたコード カバレッジを得る唯一のチャンスです。
  • 統合テストには時間がかかります(外部リソースへのアクセスのため)。1 つの統合テストの実行中に、数千の単体テストを実行できます。したがって、多くの組み合わせをテストするには、単体テストを使用する必要があります...
  • 特定のリソース (ハードウェア、ライセンスなど) へのアクセスが必要な統合テストは、多くの場合、時間や規模に制限があります。リソースが他のプロジェクトと共有されている場合、各プロジェクトはそれらを 1 日に数時間しか使用しない可能性があります。排他的アクセスであっても、1 台のマシンしか使用できない可能性があるため、テストを並行して実行することはできません。または、あなたの会社は生産用のリソース (ライセンスまたはハードウェア) を購入するかもしれませんが、開発用のリソース (または十分に早い時期) を持っていない可能性があります...
于 2009-12-24T08:06:53.017 に答える