ApplicationInsights-dotnet icon indicating copy to clipboard operation
ApplicationInsights-dotnet copied to clipboard

Add interface on TelemetryClient

Open ogborstad opened this issue 8 years ago • 26 comments

I wish TelemetryClient implemented an interface so that it would be easier to switch the client in automated tests

ogborstad avatar Oct 27 '16 09:10 ogborstad

We would typically initialize TelemetryClient with the test channel like this.

Which methods would you prefer to have in interface - high level like TrackException or lower level like Track that accepts ITelemetryChannel. Do you plan to test telemetry or just replace actual client with the one that does nothing?

SergeyKanzhelev avatar Oct 27 '16 16:10 SergeyKanzhelev

I have both use cases: replacing the client to avoid a network dependency and verify the telemetry

It looks like StubTelemetryChannel solves both cases. Then I am happy and don't really need the interface.

ogborstad avatar Oct 28 '16 11:10 ogborstad

@ogborstad I'm glad it is working for you. We still thinking what would be the best way to enable easy testing of telemetry client and use it with the DI. Thanks for asking!

SergeyKanzhelev avatar Oct 28 '16 16:10 SergeyKanzhelev

@SergeyKanzhelev Is there any update here? Did the team decide not have an interface at all?

I believe having an Interface can help easily mock (use other advanced features) that most of the testing frameworks like Moq provide. Creating a StubTelemetryChannel is helpful but I think we can do better

GiriB avatar May 30 '19 07:05 GiriB

@GiriB for now we will proceed with the mock channel. Since there is no reason TelemetryClient will ever be used as an interface in production code - defining it will cause confusion.

SergeyKanzhelev avatar May 30 '19 14:05 SergeyKanzhelev

@SergeyKanzhelev what sort of confusion are you referring to? My team would very much benefit from having an interface for TelemetryClient so that we can use Moq to verify we are passing the correct dimensions to a metric. Yes, it is possible to do this today without Moq, but it is much more code than it needs to be.

DavidParks8 avatar Sep 23 '19 04:09 DavidParks8

@SergeyKanzhelev Your example of the stubbed telemetry channel involves using the TelemetryClient's constructor which is marked obsolete. Would be nice to have a mocked instance of TelemetryClient without all the compiler warnings that come with it today.

jake-webb-kibo avatar Dec 05 '19 22:12 jake-webb-kibo

@SergeyKanzhelev Yes, please reconsider. ^^^

Simply asking that the TelemetryClient implement an ITelemetryClient so we can verify the TrackMetric calls.

That is the right level for us to verify. Our prod code knows nothing whatsoever about ITelemetryChannels, it would be weird if its unit tests had to. Doing so in effect makes the TelemetryClient part of the unit being unit tested, and that is of no interest to us.

ishepherd avatar Feb 07 '20 00:02 ishepherd

Is there any updates on this? It seems to me that ITelemetryClient would be a very straightforward implementation and would simplify many use cases for developers, just like we have ILogger.

ovasquez avatar May 28 '20 15:05 ovasquez

@TimothyMothra @cijothomas @lmolkova @SergeyKanzhelev could one of you reopen this issue please?

The TelemetryClient should support an interface to make it nice and easy to mock out.

I never yet wrote a unit test that wanted to cover the App Insights SDK code.

ishepherd avatar Jun 05 '20 13:06 ishepherd

I'll reopen the issue for further consideration. Unfortunately, there are no work planned in this area in near term, so no guaranteed when or if this will be addressed. Azure monitor/Application Insights' overall direction is alignment with OpenTelemetry, so this can be discussed more when ApplicationInsights/OpenTelemetry integrations starts shipping ~towards end of 2020

cijothomas avatar Jun 05 '20 16:06 cijothomas

cc: @rajkumar-rangaraj as Raj will be working on ApplicationInsights/OpenTelemetry integrations.

cijothomas avatar Jun 05 '20 16:06 cijothomas

Do you have any update to share about this issue ? has it been shipped in any version (released or preview) ?

YohanSciubukgian avatar Jan 27 '21 13:01 YohanSciubukgian

No update. No work is done on changing this so far. (This is unlikely to come soon, as the long term plan is to align with OpenTelemetry)

cijothomas avatar Feb 01 '21 19:02 cijothomas

Why is it so difficult to add an interface and make a lot of developers happy? For me, I just want to test if the method TrackEvent of TelemetryClient is called.

This item is open for almost 5 years and still actual. Please implement ITelemetryClient.

hvkooten avatar Apr 07 '21 13:04 hvkooten

Can someone at least put a link to StubTelemetryChannel? It would make this a lot easier

johnstaveley avatar Jul 13 '21 13:07 johnstaveley

https://github.com/microsoft/ApplicationInsights-dotnet/blob/develop/WEB/Src/TestFramework/Shared/StubTelemetryChannel.cs

pharring avatar Jul 13 '21 21:07 pharring

Hi all, I've written a small package that acts as an interface for TelemetryClient. It just requires another registration line in your ServiceCollection (services.AddApplicationInsightsTelemetryClientInterfaces())

Then you can inject an ITelemetryClient into your class. Or more specific ones like ITelemetryEventLogger or ITelemetryTraceLogger.

Enjoy.

Github Link: https://github.com/thomhurst/ApplicationInsights.TelemetryLogger

NuGet: Install-Package TomLonghurst.ApplicationInsights.TelemetryLogger

thomhurst avatar Dec 21 '21 21:12 thomhurst

Where is this feature? We just need to verify TrackEvent() was called but can't do this currently

JackSinclairT avatar Feb 18 '22 15:02 JackSinclairT

@JackSinclairT check out https://github.com/thomhurst/ApplicationInsights.TelemetryLogger

thomhurst avatar Feb 18 '22 16:02 thomhurst

. Since there is no reason TelemetryClient will ever be used as an interface in production code - defining it will cause confusion.

The real confusing part the funky stub and that we need this GitHub issue to find the stub code/tricks

Anyway, is a Pull Request accepted?

By the way, this is the 3rd most updated issue. See Issues sorted by upvote - and it seems that number 2 is already fixed - so it's 2

304NotModified avatar Aug 30 '22 20:08 304NotModified

Adding yet another comment in support of this. This would be super useful! We just want to be able to verify that the right method from the TelemetryClient is called with the expected parameters. Don't really want to introduce a unofficial third party library to wrap it or need to code a custom wrapper, just for testing. Is this going to be re-considered please?

PlayerModu avatar Oct 14 '22 14:10 PlayerModu

Found myself again in a position where I simply needed to mock a telemetry client to pass in a dependency to satisfy the constructor when the tests themselves couldn't care about the telemetry itself.

Beating the drum for this long-standing request to be solved officially.

bhehe avatar Nov 07 '22 19:11 bhehe

Same here. It can't be that hard to add this Interface. It would make developers live much easier. Do we need wait five more years?

fjordBob avatar Jan 10 '23 08:01 fjordBob

Instead of an interface, here's a complete example using a stub telemetry channel. I've kept everything in one file and eliminated some blank lines, just for exposition purposes.

using Microsoft.ApplicationInsights;
using Microsoft.ApplicationInsights.Channel;
using Microsoft.ApplicationInsights.DataContracts;
using Microsoft.ApplicationInsights.Extensibility;
using System.Collections.Concurrent;
using Xunit;

namespace TestProject1
{
    public class UnitTest1
    {
        private ConcurrentQueue<ITelemetry> TelemetryItems { get; } = new ConcurrentQueue<ITelemetry>();

        [Fact]
        public void Test1()
        {
            var telemetryClient = CreateMockTelemetryClient();
            var componentUnderTest = new ComponentUnderTest(telemetryClient);

            componentUnderTest.Test();

            Assert.True(TelemetryItems.TryDequeue(out ITelemetry? first));
            Assert.IsType<RequestTelemetry>(first);
            Assert.Equal("ItWorks", ((RequestTelemetry)first!).Name);
        }

        private TelemetryClient CreateMockTelemetryClient()
        {
            var telemetryConfiguration = new TelemetryConfiguration
            {
                ConnectionString = "InstrumentationKey=" + Guid.NewGuid().ToString(),
                TelemetryChannel = new StubTelemetryChannel(TelemetryItems.Enqueue)
            };

            // TODO: Add telemetry initializers and processors if/as necessary.
            return new TelemetryClient(telemetryConfiguration);
        }
    }

    /// <summary>
    /// A telemetry channel that simply calls a delegate.
    /// </summary>
    internal sealed class StubTelemetryChannel : ITelemetryChannel
    {
        private readonly Action<ITelemetry> _onSend;
        public StubTelemetryChannel(Action<ITelemetry> onSend) => _onSend = onSend ?? throw new ArgumentNullException(nameof(onSend));
        public bool? DeveloperMode { get; set; }
        public string EndpointAddress { get; set; } = "";
        public void Dispose() { }
        public void Flush() { }
        public void Send(ITelemetry item) => _onSend(item);
    }

    internal class ComponentUnderTest
    {
        private TelemetryClient _telemetryClient;
        public ComponentUnderTest(TelemetryClient telemetryClient) => _telemetryClient = telemetryClient;
        public void Test()
        {
            using var operation = _telemetryClient.StartOperation<RequestTelemetry>("ItWorks");
            // TODO: Body of test
        }
    }
}

The interesting parts here are:

  • The StubTelemetryChannel which just invokes a delegate on Send.
  • Setting up a mock TelemetryClient that uses that stub channel. The delegate enqueues each telemetry item to a ConcurrentQueue that's accessible to the unit test.
  • Passing that mock TelemetryClient to the component under test. This could also be done via dependency injection if that's more suited to your environment.

Obviously, all of this can be customized as appropriate for your application and testing environment.

pharring avatar Jan 10 '23 19:01 pharring

FYI There is an excellent pr here: https://github.com/microsoft/ApplicationInsights-dotnet/pull/2761

Unfortunately there is no (usefull) response why it isn't getting merged.

304NotModified avatar Sep 19 '23 21:09 304NotModified