В целях тестирования класса вы можете извлечь из предметного класса то, что необходимо для вызова тестируемого члена, поскольку целевой элемент защищен.
Нет способа изменить / получить доступ квнутренний член, но в этом случае источник показывает, что это простая реализация
/// <summary>
/// Gets the result of evaluating filter against given log event.
/// </summary>
/// <param name="logEvent">The log event.</param>
/// <returns>Filter result.</returns>
internal FilterResult GetFilterResult(LogEventInfo logEvent)
{
return Check(logEvent);
}
Источник
Оттуда это просто вопрос обеспечения необходимых зависимостейэто позволило бы выполнить тест до его завершения.
Например.
[TestClass]
public class TenancyLogFilterTests {
[TestMethod]
public void Should_Log_LogEvent() {
//Arrange
string expectedId = Guid.NewGuid().ToString();
LogLevel expectedLevel = LogLevel.Error;
FilterResult expected = FilterResult.Log;
var context = new DefaultHttpContext();
context.Request.Headers.Add(CustomHeaders.TenantId, expectedId);
var accessor = Mock.Of<IHttpContextAccessor>(_ => _.HttpContext == context);
var level = new Dictionary<string, LogLevel> {
{ expectedId, expectedLevel }
};
var config = Mock.Of<ITenancyLoggingConfiguration>(_ => _.TenantMinLoggingLevel == level);
var subject = new TestTenancyLogFilter(config, accessor);
var info = new LogEventInfo { Level = expectedLevel };
//Act
FilterResult actual = subject.GetFilterResult(info);
//Assert - FluentAssertions
actual.Should().Be(expected);
}
class TestTenancyLogFilter : TenancyLogFilter {
public TestTenancyLogFilter(ITenancyLoggingConfiguration loggingConfigurationConfig, IHttpContextAccessor httpContextAccessor)
: base(loggingConfigurationConfig, httpContextAccessor) { }
public FilterResult GetFilterResult(LogEventInfo logEvent) {
return Check(logEvent);
}
}
}
Это позволяет изолировать тест, а также обходить ограничения, предоставляемые внешней зависимостью третьей стороны.
Фактический фильтр остается прежним без необходимости предоставлять что-либо дополнительное.
Из исходного кода кода обратите внимание, что при возникновении такой проблемы с блокировкой его следует рассматривать как проблему дизайнаи знак для извлечения сервисной абстракции.
Например
public interface ILogEventAssessor {
FilterResult GetFilterResult(LogEventInfo logEvent);
}
, реализация которого будет включатьобъясните, что было сделано в пользовательском фильтре TenancyLogFilter
и добавлено в целевой класс
private readonly ILogEventAssessor service;
//...assumed injected service
private void ReconfigureNlog(object state) {
var nlogConfig = ConstructNlogConfiguration();
foreach (var rule in nlogConfig.LoggingRules) {
rule.Filters.Add(new WhenMethodFilter(ShouldLogEvent));
}
// TODO: maybe no need to reconfigure every time but just modify filter reference?
NLog.Web.NLogBuilder.ConfigureNLog(nlogConfig);
}
private FilterResult ShouldLogEvent(LogEventInfo logEvent) {
return service.GetFilterResult(logEvent);
}
//...
Теперь действительно нет необходимости проверять сторонний фильтр для проверки вашей логики.
Вы можете проверить свою реализацию ILogEventAssessor
, чтобы проверить свою собственную логику в отдельности.