8

私はMVCウェブアプリケーションを持っており、私はDIのためにSimple Injectorを使っています。私のコードのほとんどは単体テストの対象です。しかし、いくつかのコントローラでいくつかのテレメトリコールを追加したので、依存関係を設定する際に問題があります。ユニットテストでのアプリケーションインサイトの使用

テレメトリコールは、Microsoft AzureでホストされているApplication Insightsサービスにメトリックを送信するためのものです。このアプリはAzureで動作していないだけで、ISSのサーバです。 AIポータルでは、テレメトリライブラリを使用して送信したカスタムイベントなど、アプリケーションに関するあらゆる種類のことがわかります。その結果、コントローラには、Microsoft.ApplicationInsights.TelemetryClientのインスタンスが必要です。このインスタンスにはInterfaceはなく、密接なクラスで、2つのコンストラクタがあります。私はそうのようにそれを登録してみました(ハイブリッドライフスタイルは、私は完全を期すためにそれを含め、この質問には無関係です):

 // hybrid lifestyle that gives precedence to web api request scope 
     var requestOrTransientLifestyle = Lifestyle.CreateHybrid(
      () => HttpContext.Current != null, 
      new WebRequestLifestyle(), 
      Lifestyle.Transient); 

     container.Register<TelemetryClient>(requestOrTransientLifestyle); 

問題はTelemetryClientは2つのコンストラクタを持っているため、SIは不平を言うと、検証に失敗したということです。コンテナのコンストラクタの解決動作をオーバーライドする方法を示す記事を見つけましたが、それはかなり複雑です。

私がTelemetryClientを注入された依存性にしない(クラスに新しいものを作成するだけの場合)、ユニットの実行ごとにそのテレメトリーがAzureに送信されるでしょうか?多くの偽のデータを作成しますか?または、Application Insightsがユニットテストで実行され、データを送信していないことを知るには十分にスマートですか?

この問題への「洞察」は何か大変ありがとうございます。

おかげ

+2

私は質問のAI側を助けることはできませんが、登録はで簡単に行うことができます特定のコンストラクタをターゲットとするデリゲートを登録します: 'container.Register(()=> new TelemetryClient(/ *ターゲットにするコンストラクタ* /)、requestOrTransientLifestyle);また、[DefaultScopedLifestyle](https://simpleinjector.readthedocs.org/en/latest/lifetimes.html#scoped) – qujck

+2

をチェックしてください。単体テストについては、必要に応じて模擬できるTelemetryClient上に独自の抽象化を定義する必要があります。ユニットテストはAzureと対話してはいけません。 – qujck

+0

あなたのカスタムハイブリッドスコープは私に心配です。 Web要求ライフスタイルと過渡的なライフスタイルを混在させることは、通常、良い方法ではありません。あなたはなぜこのような混合ライフスタイルが必要なのか説明できますか? – Steven

答えて

14

ないインタフェースを持たず、2つのコンストラクタと、密閉されたクラスであるMicrosoft.ApplicationInsights.TelemetryClient、。

TelemetryClientはフレームワークタイプであり、framework types should not be auto-wired by your containerである。

コンテナのコンストラクタ解決動作をオーバーライドする方法を示す記事が見つかりましたが、それはかなり複雑に思えます。

これは、an anti-patternなので、複数のコンストラクタを持つコンポーネントを作成しないようにするため、この複雑さは意図的です。

container.Register<TelemetryClient>(() => 
    new TelemetryClient(/*whatever values you need*/), 
    requestOrTransientLifestyle); 

それとも単位で実行されている知っているのに十分スマートアプリケーションの洞察です:代わりに自動配線を使用しての@qujckがすでに指摘したように

することは、あなたは、単に以下の登録を行うことができますテストし、データを送信しない?

非常にありそうもありません。このTelemetryClientに依存するクラスをテストする場合は、ユニットテストが壊れやすくなったり、遅くなったり、Insightデータが汚染されたりしないように、代わりに偽の実装を使用することをお勧めします。しかし、テストが問題ではないとしても、Dependency Inversion Principleによれば、(1)自分のアプリケーションによって定義された抽象化(2)に依存する必要があります。 TelemetryClientを使用すると、両方の点で不合格になります。

代わりに、TelemetryClientの1つ(または複数の場合もあります)の抽象定義を定義してください。具体的にはに合わせてです。したがって、TelemetryClientのAPIを可能な100の方法で模倣しようとしないで、コントローラが実際に使用するインターフェイス上のメソッドを定義し、をできるだけ単純なものにするだけで、コントローラのコードを簡単にすることができます。ユニットテストが簡単になります。

適切な抽象を定義したら、TelemetryClientを内部的に使用するアダプタ実装を作成できます。次のようにこのアダプタを登録し、私がイメージ:

ここ
container.RegisterSingleton<ITelemetryLogger>(
    new TelemetryClientAdapter(new TelemetryClient(...))); 

私はTelemetryClientは、スレッドセーフであるとシングルトンとして働くことができることを前提としています。

container.RegisterSingleton<ITelemetryLogger>(
    new TelemetryClientAdapter(() => new TelemetryClient(...))); 

ここアダプタがまだシングルトンですが、TelemetryClientを作成することができますデリゲートを備えている。そうでなければ、あなたはこのような何かを行うことができます。もう1つの方法は、アダプタに内部でTelemetryClientを作成させる(おそらく処分する)ことです。これにより、登録がさらに簡単になります。

container.RegisterSingleton<ITelemetryLogger>(new TelemetryClientAdapter()); 
+2

この詳細な回答ありがとうございます。 Steveと@qujckが示唆したように、私の主な質問は、私の選択のコンストラクタにテレメトリクライアントを登録するためのシンプルな一行で答えられました。(スティーブの答えにはタイプミスがあります。この質問を投稿した後、単体テストの問題と同じ解決策に着きました。TelemetryClientを自分のデザインのシンプルなクラスにラップし、必要なメソッドを公開し、インターフェイスを作成しました。ユニットテストでは、その単純なラッパークラスはMoqでMockedされています。 –

2

抽象/ラッパーパスを使用したくない場合は、あなたのテストでは、AppInsightsエンドポイントを模擬軽量httpサーバ(ASP.NETコアでは簡単です)に向けることができます。

appInsightsSettings.json

"ApplicationInsights": { 
    "Endpoint": "http://localhost:8888/v2/track" 
} 

ASP.NETコアに「TESTSERVER」を設定する方法http://josephwoodward.co.uk/2016/07/integration-testing-asp-net-core-middleware

関連する問題