Pregunta

Quiero manejar una excepción ManagementException solo para un Código de error específico y tengo problemas para escribir la prueba de la unidad. Normalmente, escribiría la prueba para que sea algo como lo siguiente:

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

...

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

...

Sin embargo, esto no establece el ErrorCode al que quiero en particular, de hecho ManagementException no tiene un constructor que establezca este valor.

¿Cómo se puede hacer esto?

(Tenga en cuenta que estoy usando RhinoMocks como mi marco de trabajo burlón, pero supongo que esto es independiente del marco; todo lo que necesito saber aquí es cómo crear una ManagementException que tenga un valor específico de ErrorCode. También he encontrado algunas referencias a un método System.Management.ManagementException.ThrowWithExtendedInfo (ManagementStatus errorCode) en línea, pero esto no parece ser de acceso público).

¿Fue útil?

Solución

El menor esfuerzo para superar este obstáculo sería un método auxiliar / utilidad estático que utiliza la reflexión para hackear la ranura en el código de error requerido. Usando el reflector más excelente, veo que hay un privado '' código de error '' campo, que solo se establece a través de ctors internos definidos en ManagementException. Entonces :)

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;
      }
   }

Verificado que funciona

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

Aunque generalmente frunzo el ceño ante la reflexión en las pruebas , este es uno de los raros casos en los que es necesario / útil.
HTH

Otros consejos

Derive una clase de ManagementException y oculte la implementación del código de error con la suya. Haz que tu simulacro devuelva esta clase.

Tenga un método o clase muy simple y pequeño que detecte esa excepción y obtenga el código de error, y luego lo pase a la clase real que hace el trabajo. Bajo prueba, reemplace ese código con pasar directamente a la clase real lo que pasaría cuando obtenga ese código de error.

La forma más obvia es subclasificar la excepción, pero si eso no funciona, entonces el código que lo atrapa e inmediatamente arroja su propia excepción que le permite exponer ese código sería otra opción.

Subclase ManagementException y en la subclase anula el captador ErrorCode (si los niveles normales de protección le impiden hacerlo, tal vez la introspección pueda acercarlo). Cualquier código que maneje ManagementException pero nunca haya escuchado acerca de su subclase específica debe manejar su subclase "como si" después de todo, fue la ManagementException la que intentas simular con fines de prueba.

Editar : es concebible que ErrorCode simplemente no pueda ser anulado (odio los lenguajes que son TAN rígidos que pueden dejar de probar de esta manera, pero no pueden negar que existen; -). En este caso, Dependency Injection aún puede salvarlo: la DI es uno de mis patrones favoritos para las pruebas.

El propósito de

DI en las pruebas es desacoplar el código bajo prueba de suposiciones rígidas que inhibirían la capacidad de prueba, y eso es justo lo que tenemos aquí, aunque de forma inusual. Su código bajo prueba actualmente, por ejemplo, x.ErrorCode para obtener el código de error de excepción x. Muy bien, debe hacer, en cambio, getErrorCode (x) donde getErrorCode es un delegado que normalmente solo devuelve x.ErrorCode ; y debe tener un configurador para el delegado getErrorCode , de modo que para fines de prueba, puede cambiarlo a un delegado que devuelva 23 (o cualquier valor de código de error desea simular para probar).

Los detalles pueden variar, pero la inyección de dependencia puede (entre otras cosas) ayudar a compensar algunos tipos de rigidez excesiva en los objetos que inevitablemente obtiene del sistema (o de otras bibliotecas y amp; c que no puede modificar directamente), como en este ejemplo.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top