Как установить ErrorCode для ManagementException? - PullRequest
1 голос
/ 18 июня 2009

Я хочу обработать исключение ManagementException только для определенного ErrorCode, и у меня возникают проблемы при написании модульного теста для него. Обычно я написал бы тест так, чтобы он был примерно таким:

Searcher search = MockRepository.GenerateMock<Searcher>(); 
// wrapper for ManagementObjectSearcher

...

search.Expect(s => s.Get()).Throw(new ManagementException());

...

Однако это не устанавливает ErrorCode на тот, который мне нужен, в частности, ManagementException не имеет конструктора, который устанавливает это значение.

Как это можно сделать?

(Обратите внимание, что я использую RhinoMocks в качестве моей среды разработки, но я предполагаю, что она не зависит от среды; все, что мне нужно знать здесь, это как создать ManagementException, который имеет конкретное значение ErrorCode. Также я нашел некоторые ссылки System.Management.ManagementException.ThrowWithExtendedInfo(ManagementStatus errorCode) метод в сети, но он не является общедоступным).

Ответы [ 4 ]

3 голосов
/ 06 июля 2009

Наименьшее усилие преодолеть это препятствие - статический вспомогательный / служебный метод, который использует отражение для взлома слота в требуемом коде ошибки. Используя самый лучший Reflector, я вижу, что есть частное поле errorCode, которое устанавливается только через внутренние ctors, определенные в ManagementException. Итак:)

public static class EncapsulationBreaker
   {
      public static ManagementException GetManagementExceptionWithSpecificErrorCode(ManagementStatus statusToBeStuffed)
      {
         var exception = new ManagementException();
         var fieldInfo = exception.GetType().GetField("errorCode", 
            BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.GetField | BindingFlags.DeclaredOnly);
         fieldInfo.SetValue(exception, statusToBeStuffed);
         return exception;
      }
   }

Проверено, что работает

[Test]
      public void TestGetExceptionWithSpecifiedErrorCode()
      {
         var e = EncapsulationBreaker.GetManagementExceptionWithSpecificErrorCode(ManagementStatus.BufferTooSmall);
         Assert.AreEqual(ManagementStatus.BufferTooSmall, e.ErrorCode);
      }

Хотя Я, как правило, недоволен отражением в тестах , это один из редких случаев, когда это необходимо / полезно.
НТН

1 голос
/ 06 июля 2009

Получите класс из ManagementException и скройте реализацию кода ошибки с вашим собственным. Пусть ваш макет вернет этот класс.

0 голосов
/ 06 июля 2009

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

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

0 голосов
/ 06 июля 2009

Я бы подкласс ManagementException и в подклассе переопределил геттер ErrorCode (если нормальные уровни защиты мешают вам сделать это, возможно, интроспекция может приблизить вас). Любой код, который обрабатывает ManagementException, но никогда не слышал о вашем конкретном подклассе, должен обрабатывать ваш подкласс «как если бы», в конце концов, ManagementException вы пытаетесь смоделировать для целей тестирования.

Редактировать : вполне возможно, что ErrorCode просто невозможно переопределить (я ненавижу настолько жесткие языки, что они могут прекратить тестирование таким образом, но не могут отрицать, что они существуют ;-). В этом случае Внедрение зависимостей все еще может спасти вас - DI - один из моих любимых шаблонов для тестирования.

Цель DI в тестировании - отделить тестируемый код от жестких допущений, которые будут препятствовать тестируемости - и это только то, что мы имеем здесь, хотя и в необычной форме. Ваш тестируемый код в настоящее время, скажем, x.ErrorCode, чтобы получить код ошибки исключения x. Очень хорошо, тогда он должен сделать вместо этого getErrorCode(x), где getErrorCode - делегат, который обычно просто делает return x.ErrorCode; и он должен иметь установщик для делегата getErrorCode, чтобы в целях тестирования вы могли изменить его на делегат, который выполняет return 23 (или любое другое значение кода ошибки, которое вы хотите смоделировать для тестирования).

Детали могут различаться, но внедрение зависимостей может (среди прочего) помочь компенсировать некоторые виды чрезмерной жесткости в объектах, которые вы неизбежно получаете из системы (или из других библиотек и т.д., которые вы не можете напрямую изменить), как в этом примере.

...