Using Application Insights with Unit Tests?

前端 未结 5 2117
时光取名叫无心
时光取名叫无心 2020-12-14 08:15

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 contr

5条回答
  •  鱼传尺愫
    2020-12-14 08:44

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

    This TelemetryClient is a framework type and framework types should not be auto-wired by your container.

    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.

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

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

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

    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.

    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.

    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(
        new TelemetryClientAdapter(new 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(
        new TelemetryClientAdapter(() => new 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(new TelemetryClientAdapter());
    

提交回复
热议问题