在单元测试中使用Application Insights? [英] Using Application Insights with Unit Tests?

查看:158
本文介绍了在单元测试中使用Application Insights?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个MVC Web应用程序,并且正在使用Simple Injector进行DI.我的几乎所有代码都包含在单元测试中.但是,既然我已经在某些控制器中添加了一些遥测调用,则我在设置依赖项时遇到了麻烦.

I have an MVC web app, and I'm using Simple Injector for DI. Almost all my code is covered by unit tests. However, now that I've added some telemetry calls in some controllers, I'm having trouble setting up the dependencies.

遥测调用用于将度量标准发送到Microsoft Azure托管的Application Insights服务.该应用程序不在Azure中运行,而仅在具有ISS的服务器上运行. AI门户会告诉您有关应用程序的各种信息,包括您使用遥测库发送的任何自定义事件.结果,该控制器需要一个Microsoft.ApplicationInsights.TelemetryClient实例,该实例不具有接口,并且是带有2个构造函数的密封类.我尝试过这样注册(混合生活方式与该问题无关,我只是为了完整而将其包括在内):

The telemetry calls are for sending metrics to the Microsoft Azure-hosted Application Insights service. The app is not running in Azure, just a server with ISS. The AI portal tells you all kinds of things about your application, including any custom events you send using the telemetry library. As a result, the controller requires an instance of Microsoft.ApplicationInsights.TelemetryClient, which has no Interface and is a sealed class, with 2 constructors. I tried registering it like so (the hybrid lifestyle is unrelated to this question, I just included it for completeness):

// 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会抱怨并且验证失败.我发现了一篇帖子,展示了如何重写容器的构造函数解析行为,但这似乎很复杂.首先,我想备份并提出以下问题:

The problem is that since TelemetryClient has 2 constructors, SI complains and fails validation. I found a post showing how to override the container's constructor resolution behavior, but that seems pretty complicated. First I wanted to back up and ask this question:

如果我不使TelemetryClient成为注入的依赖项(只需在类中创建一个New依赖项),该遥测性是否会在每次单元测试运行时发送到Azure,从而创建大量错误数据?还是Application Insights足够聪明才能知道它正在单元测试中运行,而不发送数据?

If I don't make the TelemetryClient an injected dependency (just create a New one in the class), will that telemetry get sent to Azure on every run of the unit test, creating lots of false data? Or is Application Insights smart enough to know it is running in a unit test, and not send the data?

任何对此问题的见解"将不胜感激!

Any "Insights" into this issue would be much appreciated!

谢谢

推荐答案

Microsoft.ApplicationInsights.TelemetryClient,它没有接口,是一个带有2个构造函数的密封类.

Microsoft.ApplicationInsights.TelemetryClient, which has no Interface and is a sealed class, with 2 constructors.

TelemetryClient是框架类型,并且框架类型不应由您的容器自动接线.

我找到了一篇帖子,展示了如何重写容器的构造函数解析行为,但这似乎很复杂.

I found a post showing how to override the container's constructor resolution behavior, but that seems pretty complicated.

是的,这种复杂性是有意的,因为我们想阻止人们使用多个构造函数创建组件,因为这是

Yep, this complexity is deliberate, because we want to discourage people from creating components with multiple constructors, because this is an anti-pattern.

正如@qujck所指出的那样,您可以进行以下注册,而不是使用自动装配:

Instead of using auto-wiring, you can, as @qujck already pointed out, simply make the following registration:

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

还是说Application Insights足够聪明才能知道它正在单元测试中运行,并且不发送数据?

Or is Application Insights smart enough to know it is running in a unit test, and not send the data?

极不可能.如果要测试依赖于此TelemetryClient的类,则最好改用伪造的实现,以防止单元测试变得脆弱,缓慢或污染Insight数据.但是,即使不必担心测试,根据依赖关系倒置原则,您也应该依赖(1) (2)由您自己的应用程序定义.使用TelemetryClient时,这两个点都会失败.

Very unlikely. If you want to test the class that depends on this TelemetryClient, you better use a fake implementation instead, to prevent your unit test to either become fragile, slow, or to pollute your Insight data. But even if testing isn't a concern, according to the Dependency Inversion Principle you should depend on (1) abstractions that are (2) defined by your own application. You fail both points when using the TelemetryClient.

您应该做的是在TelemetryClient上定义一个(或什至多个)抽象,这些抽象是特别为您的应用程序量身定制的.因此,请勿尝试使用可能的100种方法模仿TelemetryClient的API,而应仅在控制器实际使用的接口上定义方法,并使它们尽可能简单 使控制器的代码更简单,并且使单元测试也更简单.

What you should do instead is define one (or perhaps even multiple) abstractions over the TelemetryClient that are especially tailored for your application. So don't try to mimic the TelemetryClient's API with its possible 100 methods, but only define methods on the interface that your controller actually uses, and make them as simple as possible so you can make both the controller's code simpler -and- your unit tests simpler.

定义良好的抽象之后,可以创建内部使用TelemetryClient的适配器实现.我为您注册此适配器的图像如下:

After you defined a good abstraction, you can create an adapter implementation that uses the TelemetryClient internally. I image you register this adapter as follows:

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

在这里,我认为TelemetryClient是线程安全的,可以作为单例工作.否则,您可以执行以下操作:

Here I assume that the TelemetryClient is thread-safe and can work as a singleton. Otherwise, you can do something like this:

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

此处,适配器仍然是单例,但是提供了一个允许创建TelemetryClient的委托.另一种选择是让适配器在内部创建(或处置)TelemetryClient.这也许会使注册更加简单:

Here the adapter is still a singleton, but is provided with a delegate that allows creation of the TelemetryClient. Another option is to let the adapter create (and perhaps dispose) the TelemetryClient internally. That would perhaps make the registration even simpler:

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

这篇关于在单元测试中使用Application Insights?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆