Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add interface on TelemetryClient #342

Open
ogborstad opened this issue Oct 27, 2016 · 26 comments
Open

Add interface on TelemetryClient #342

ogborstad opened this issue Oct 27, 2016 · 26 comments

Comments

@ogborstad
Copy link

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

@SergeyKanzhelev
Copy link
Contributor

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?

@ogborstad
Copy link
Author

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.

@SergeyKanzhelev
Copy link
Contributor

@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!

@GiriB
Copy link

GiriB commented May 30, 2019

@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

@SergeyKanzhelev
Copy link
Contributor

@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.

@DavidParks8
Copy link
Member

@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.

TimothyMothra pushed a commit that referenced this issue Oct 25, 2019
…343)

* Add tests to illustrate issue #342
* Fix issue #342
* Incorporate review feedback:
Set timestamp in OnBeginRequest.
Add a test for issue #340
Set Id instead of OperationId (Fixes #340)

* Add test for issue #333
* Implement OperationCorrelationTelemetryInitializer
Fixes issue #333

* Use UTC for start time epoch
* Use Start()/Stop() extension methods
@jake-webb-kibo
Copy link

@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.

@ishepherd
Copy link

@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.

@ovasquez
Copy link

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.

@ishepherd
Copy link

@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.

@cijothomas
Copy link
Contributor

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 cijothomas reopened this Jun 5, 2020
@cijothomas
Copy link
Contributor

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

@YohanSciubukgian
Copy link

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

@cijothomas
Copy link
Contributor

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)

@hvkooten
Copy link

hvkooten commented Apr 7, 2021

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.

@johnstaveley
Copy link

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

@pharring
Copy link
Member

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

@thomhurst
Copy link

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

@JackSinclairT
Copy link

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

@thomhurst
Copy link

@304NotModified
Copy link

304NotModified commented Aug 30, 2022

. 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

@PlayerModu
Copy link

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?

@bhehe
Copy link

bhehe commented Nov 7, 2022

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.

@fjordBob
Copy link

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?

@pharring
Copy link
Member

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.

@304NotModified
Copy link

FYI There is an excellent pr here:
#2761

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests