단위 테스트와 함께 애플리케이션 통찰력을 사용하시겠습니까?
저는 MVC 웹 앱을 가지고 있으며, DI용 Simple Injector를 사용하고 있습니다.거의 모든 코드가 단위 테스트로 적용됩니다.그러나 일부 컨트롤러에 원격 측정 호출을 추가했기 때문에 종속성을 설정하는 데 어려움을 겪고 있습니다.
원격 측정 호출은 Microsoft Azure에서 호스팅하는 Application Insight 서비스로 메트릭을 전송하기 위한 것입니다.앱은 애저에서 실행되지 않고 ISS가 있는 서버일 뿐입니다.AI 포털은 원격 측정 라이브러리를 사용하여 보내는 모든 사용자 지정 이벤트를 포함하여 응용 프로그램에 대한 모든 종류의 것을 알려줍니다.따라서 컨트롤러에 마이크로소프트 인스턴스가 필요합니다.어플통찰력.TelemetryClient는 인터페이스가 없고 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가 불만을 제기하고 검증에 실패한다는 것입니다.컨테이너의 생성자 해결 동작을 재정의하는 방법을 보여주는 게시물을 찾았지만, 그것은 꽤 복잡한 것 같습니다.먼저 백업하고 다음과 같은 질문을 하고 싶었습니다.
Telemetry Client를 주입 종속성으로 만들지 않으면(클래스에서 새 클라이언트만 생성) 장치 테스트를 실행할 때마다 해당 원격 측정이 Azure로 전송되어 많은 잘못된 데이터가 생성됩니까?또는 Application Insights는 데이터를 전송하지 않고 단위 테스트에서 실행 중임을 알 수 있을 정도로 영리합니까?
이 문제에 대한 "견해"를 주시면 감사하겠습니다!
감사해요.
Application Insights에는 유닛 테스트의 예가 있습니다.TelemetryClient
.TelemetryChannel
.
TelemetryChannel
ITelemetryChannel
그래서 조롱하고 주입하기가 꽤 쉽습니다.메시지를 에 이예에는기다나수수있다집습니할중에에서 할 수 .Items
단언을 위하여
public class MockTelemetryChannel : ITelemetryChannel
{
public IList<ITelemetry> Items
{
get;
private set;
}
...
public void Send(ITelemetry item)
{
Items.Add(item);
}
}
...
MockTelemetryChannel = new MockTelemetryChannel();
TelemetryConfiguration configuration = new TelemetryConfiguration
{
TelemetryChannel = MockTelemetryChannel,
InstrumentationKey = Guid.NewGuid().ToString()
};
configuration.TelemetryInitializers.Add(new OperationCorrelationTelemetryInitializer());
TelemetryClient telemetryClient = new TelemetryClient(configuration);
container.Register<TelemetryClient>(telemetryClient);
마이크로소프트.어플통찰력.TelemetryClient는 인터페이스가 없고 2개의 생성자가 있는 밀폐된 클래스입니다.
것이.TelemetryClient
는 프레임워크 유형이며 프레임워크 유형은 컨테이너에 의해 자동으로 배선되어서는 안 됩니다.
컨테이너의 생성자 해결 동작을 재정의하는 방법을 보여주는 게시물을 찾았지만, 그것은 꽤 복잡한 것 같습니다.
네, 이 복잡성은 의도적입니다. 왜냐하면 우리는 사람들이 여러 개의 생성자로 구성 요소를 만드는 것을 막고 싶기 때문입니다. 왜냐하면 이것은 반패턴이기 때문입니다.
자동 배선을 사용하는 대신, @qujck가 이미 지적했듯이 다음과 같은 등록을 간단히 할 수 있습니다.
container.Register<TelemetryClient>(() =>
new TelemetryClient(/*whatever values you need*/),
requestOrTransientLifestyle);
또는 Application Insights는 데이터를 전송하지 않고 단위 테스트에서 실행 중임을 알 수 있을 정도로 영리합니까?
가능성이 매우 낮습니다.하려면 다음과 같이 .TelemetryClient
장치 테스트가 취약해지거나 느려지거나 Insight 데이터를 오염시키는 것을 방지하려면 가짜 구현을 사용하는 것이 좋습니다.그러나 테스트가 문제가 되지 않더라도 종속성 반전 원칙에 따라 (1) 자신의 애플리케이션에 의해 정의된 (2) 추상화에 의존해야 합니다.사용 시 두 점 모두 실패합니다.TelemetryClient
.
대신 수행해야 할 작업은 다음을 통해 하나의(또는 여러 개의) 추상화를 정의하는 것입니다.TelemetryClient
특히 사용자의 애플리케이션에 맞게 조정됩니다.그러니 흉내를 내려고 하지 마세요.TelemetryClient
가능한 100개의 메서드를 포함하는 의 API는 컨트롤러가 실제로 사용하는 인터페이스에서만 메서드를 정의하고 컨트롤러의 코드를 최대한 단순하게 하여 장치 테스트를 단순화할 수 있도록 합니다.
추상화를 하여 어댑터 할 수 .TelemetryClient
내부적으로이 어댑터를 다음과 같이 등록하는 것이 이미지입니다.
container.RegisterSingleton<ITelemetryLogger>(
new TelemetryClientAdapter(new TelemetryClient(...)));
여기서 나는 가정합니다.TelemetryClient
스레드 세이프이며 싱글톤으로 작동할 수 있습니다.그렇지 않으면 다음과 같은 작업을 수행할 수 있습니다.
container.RegisterSingleton<ITelemetryLogger>(
new TelemetryClientAdapter(() => new TelemetryClient(...)));
여기서 어댑터는 여전히 싱글톤이지만 다음을 만들 수 있는 대리자가 제공됩니다.TelemetryClient
또 다른 옵션은 어댑터가 다음을 생성하도록 하는 것입니다(그리고 아마도 폐기할 것입니다.TelemetryClient
더 간단해질 입니다.그러면 등록이 훨씬 더 간단해질 것입니다.
container.RegisterSingleton<ITelemetryLogger>(new TelemetryClientAdapter());
저는 모의 원격 측정 채널을 작성하고 그것을 제 시험에 주입하기 위해 조쉬 로스타드의 기사를 사용함으로써 많은 성공을 거두었습니다.모의 목표는 다음과 같습니다.
public class MockTelemetryChannel : ITelemetryChannel
{
public ConcurrentBag<ITelemetry> SentTelemtries = new ConcurrentBag<ITelemetry>();
public bool IsFlushed { get; private set; }
public bool? DeveloperMode { get; set; }
public string EndpointAddress { get; set; }
public void Send(ITelemetry item)
{
this.SentTelemtries.Add(item);
}
public void Flush()
{
this.IsFlushed = true;
}
public void Dispose()
{
}
}
그리고 제 테스트에서, 모의 실험을 스핀업하기 위한 로컬 방법:
private TelemetryClient InitializeMockTelemetryChannel()
{
// Application Insights TelemetryClient doesn't have an interface (and is sealed)
// Spin -up our own homebrew mock object
MockTelemetryChannel mockTelemetryChannel = new MockTelemetryChannel();
TelemetryConfiguration mockTelemetryConfig = new TelemetryConfiguration
{
TelemetryChannel = mockTelemetryChannel,
InstrumentationKey = Guid.NewGuid().ToString(),
};
TelemetryClient mockTelemetryClient = new TelemetryClient(mockTelemetryConfig);
return mockTelemetryClient;
}
마지막으로, 테스트를 실행합니다!
[TestMethod]
public void TestWidgetDoSomething()
{
//arrange
TelemetryClient mockTelemetryClient = this.InitializeMockTelemetryChannel();
MyWidget widget = new MyWidget(mockTelemetryClient);
//act
var result = widget.DoSomething();
//assert
Assert.IsTrue(result != null);
Assert.IsTrue(result.IsSuccess);
}
추상화/포장지 경로를 따라 내려가지 않으려는 경우.테스트에서 AppInsights 엔드포인트를 단순하게 모의 경량 http 서버(ASP에서는 사소한 것)로 지정할 수 있습니다.NET Core).
appInsightsSettings.json
"ApplicationInsights": {
"Endpoint": "http://localhost:8888/v2/track"
}
ASP에서 "TestServer"를 설정하는 방법NET Core http://josephwoodward.co.uk/2016/07/integration-testing-asp-net-core-middleware
추상화 경로를 사용하지 않는 또 다른 옵션은 테스트를 실행하기 전에 원격 측정을 사용하지 않도록 설정하는 것입니다.
TelemetryConfiguration.Active.DisableTelemetry = true;
여기에 있는 다른 작업을 기반으로 합니다.
- 채널 생성 - 필요한 경우 원격 측정 테스트에 사용할 수 있습니다.
public class MockTelemetryChannel : ITelemetryChannel
{
public ConcurrentBag<ITelemetry> SentTelemtries = new();
public bool IsFlushed { get; private set; }
public bool? DeveloperMode { get; set; }
public string EndpointAddress { get; set; }
public void Send(ITelemetry item)
{
this.SentTelemtries.Add(item);
}
public void Flush()
{
this.IsFlushed = true;
}
public void Dispose()
{
}
}
- 작고 정적인 공장 클래스를 사용합니다.
public static class MockTelemetryClient
{
public static TelemetryClient Create()
{
var mockTelemetryChannel = new MockTelemetryChannel();
var mockTelemetryConfig = new TelemetryConfiguration
{
TelemetryChannel = mockTelemetryChannel,
InstrumentationKey = Guid.NewGuid().ToString()
};
var mockTelemetryClient = new TelemetryClient(mockTelemetryConfig);
return mockTelemetryClient;
}
}
- 불러
MockTelemetryClient.Create()
당신의 것을 얻기 위해TelemetryClient
- 이익
제 동료가 이러한 핵심 원격 측정 유형(예:)에 대한 추상화를 소개하는 유용한 라이브러리를 작성했습니다.ITelemetryClient
그리고.IMetric
).
https://github.com/thomhurst/ApplicationInsights.TelemetryLogger
구현이 매우 쉽습니다.생산 코드의 내용을 거의 변경할 필요가 없으며 테스트에서 조롱하는 것은 쉬운 일이 됩니다.README에서 발췌한 내용입니다.
종속성 주입
불러AddApplicationInsightsTelemetry()
정상적으로, 그리고 나서 전화.AddApplicationInsightsTelemetryClientInterfaces()
public void ConfigureServices(IServiceCollection services)
{
services
.AddApplicationInsightsTelemetry()
.AddApplicationInsightsTelemetryClientInterfaces();
}
IT 원격 측정 클라이언트
다음과 같은 용도를 원합니다.TelemetryClient
주입ITelemetryClient
당신의 수업에 들어갑니다.사용 가능한 모든 방법이 있습니다.TelemetryClient
(예: 내부 또는 더 이상 사용되지 않는 방법은 제외).
public class MyClass
{
private readonly ITelemetryClient _telemetryClient;
public MyClass(ITelemetryClient telemetryClient)
{
_telemetryClient = telemetryClient;
}
public void DoSomething()
{
_telemetryClient.TrackTrace("Something happened");
}
}
언급URL : https://stackoverflow.com/questions/33815397/using-application-insights-with-unit-tests
'code' 카테고리의 다른 글
왜 MongoDB가 SQL DB보다 훨씬 빠른지에 대한 구체적이고 구체적인 이유가 있습니까? (0) | 2023.05.08 |
---|---|
로컬에서 실행되는 도커 컨테이너에서 Azure Keyvault에 액세스하는 방법은 무엇입니까? (0) | 2023.05.08 |
텍스트 상자를 부동값으로 바인딩합니다.도트/콤마를 입력할 수 없습니다. (0) | 2023.05.08 |
SQL 테이블의 레코드를 복사하면서 새 행의 고유 ID를 스왑 아웃하려면 어떻게 해야 합니까? (0) | 2023.05.08 |
일부 Microsoft 언어를 "Visual"이라고 부르는 이유는 무엇입니까? (Visual C#, Visual Basic)NET, 비주얼 C++) (0) | 2023.05.08 |