Тест не подхватывается покрытием кода (стандарт c # .net) - PullRequest
0 голосов
/ 18 октября 2018

Я реализовал свой собственный регистратор, который следует интерфейсу ILogger.Внутренне, у него есть клиент AppInsights, и это то, к чему фактически ведет мой регистратор.Вот упрощенная версия моего класса:

public class AppInsightsLogger : ILogger
{
    internal TelemetryClient Client { get; set; }

    public AppInsightsLogger(string instrumentationKey)
    {
        TelemetryConfiguration.Active.InstrumentationKey = instrumentationKey;
        Client = new TelemetryClient();
    }

    public void Log<T>(LogLevel logLevel, EventId eventId, T state, Exception exception,
        Func<T, Exception, string> formatter)
    {
        if (string.IsNullOrEmpty(eventId.Name))
        {
            StackFrame frame = new StackFrame(1); 
            var method = frame.GetMethod();
            var type = method.DeclaringType;
            var name = method.Name;

            eventId = new EventId(eventId.Id == 0 ? BitConverter.ToInt32(Guid.NewGuid().ToByteArray(), 0) : eventId.Id, $"{type}:{name}");
        }

        var props = new Dictionary<string, string>
        {
            { "EventId", eventId.Id.ToString() },
            { "EventName", eventId.Name }
        };

        var telemetry = new EventTelemetry(eventId.Name);

        if (!string.IsNullOrEmpty(state.ToString()))
        {
            telemetry.Properties.Add("SummaryMessage", state.ToString());
        }

        foreach (var property in props)
        {
            telemetry.Properties.Add(property);
        }

        Client.TrackEvent(telemetry);
    }
}

Что я хотел бы проверить (потенциально неправильно, пожалуйста, также посоветуйте), так это то, что когда я вызываю мой метод AppInsightsLogger classes Log, он на самом делепытается вызвать метод TrackEvent TelemetryClient.Я думал о тесте, подобном следующему:

    [Fact, IsUnit]
    public void Test_Telemetry_Log()
    {
        var mock = new Mock<ILogger>();

        mock.Setup(m => 
             m.Log<string>(It.IsAny<LogLevel>(), It.IsAny<EventId>(), It.IsAny<string>(), null, null));

        mock.Object.Log(LogLevel.Information, new EventId(1, "test"), "test", null, null);

        mock.Verify();
    }

НО, когда я запускаю этот тест (который проходит нормально), он не выглядит так, как покрывается моим монитором покрытия кода (Jetbrain's dotCoverage ).

enter image description here

Есть какие-нибудь идеи, как правильно выполнить этот тест, чтобы правильно покрыть код?Я также использую Moq .

Проблема в том, что это поддельный экземпляр?Я не могу издеваться над TelemetryClient, так как моей другой мыслью было протестировать этот экземпляр AppInsightsLogger, а затем проверить, что TelemetryClient.log называется НО, это закрытый класс, который усложняет этот тест: - /

Заранее спасибо за любые советы!!ПРИМЕЧАНИЕ: я довольно новичок в написании тестов - я понимаю концепции, но на самом деле не выполняю.

1 Ответ

0 голосов
/ 18 октября 2018

Ну, ваш код не покрыт, потому что он не выполняется.Вы создали фиктивный объект, а затем вызвали метод для этой установки.Вместо вашего реального кода moq включается и просто возвращает значения, которые вы установили.

Поэтому, когда вы вызываете:

mock.Object.Log(LogLevel.Information, new EventId(1, "test"), "test", null, null);

, он не входит в код, он ищет соответствующий наборподнимает ваш фиктивный объект и находит его:

mock.Setup(m => 
             m.Log<string>(It.IsAny<LogLevel>(), It.IsAny<EventId>(), It.IsAny<string>(), null, null));

В вашем тесте вы должны на самом деле создать экземпляр AppInsightsLogger и вызвать в нем журнал вызовов.Спрячьте своего TelemetryClient за интерфейсом, смейтесь над этим и проверяйтеНе вдаваясь в подробности, он будет выглядеть так:

public interface ITelemetryClientWrapper{
 void TrackEvent();
}

public class MyTelemetryClient : ITelemetryClientWrapper{
 public void TrackEvent(){
   // Use real TelemetryClient here, I guess it's not your class, right? If it's your class, just extract an interface from it
 }
}

Вставьте его в свой Logger в конструкторе или свойстве (используйте DI):

public class MyLogger{
  public MyLogger(ITelemetryClientWrapper wrapper){
  }
}

И, наконец, в вашем тесте:

var telemetryMock = new Mock<ITelemetryClientWrapper>();
var target = new MyLogger(telemetryMock.Object);
target.Log(...);

telemetryMock.Verify(c => c.TrackEvent());

Короче говоря: вы не издеваетесь над классом, который тестируете, вы высмеиваете зависимости этого класса.Чтобы при тестировании вашего класса код из других классов не выполнялся и не влиял на результаты теста.

...