utilizar try todas tipos que programacion para manejar las existen excepciones errores como catch capturar c# visual-studio-2010 .net-4.0 code-contracts

try - todas las excepciones en c#



¿Cómo es que no puedes atrapar las excepciones del Contrato de Código? (4)

System.Diagnostics.Contracts.ContractException no está accesible en mi proyecto de prueba. Tenga en cuenta que este código es simplemente yo mismo jugando con mi nueva y brillante copia de Visual Studio, pero me gustaría saber qué estoy haciendo mal.

Estoy usando la edición profesional de VS, por lo tanto, no tengo una comprobación estática. Para seguir usando contratos de código (lo que me gusta) pensé que la única forma en que mi método puede funcionar es detectar la excepción que se produce en el tiempo de ejecución, pero no me parece posible.

Método de prueba

[TestMethod, ExpectedException(typeof(System.Diagnostics.Contracts.ContractException))] public void returning_a_value_less_than_one_throws_exception() { var person = new Person(); person.Number(); }

Método

public int Number() { Contract.Ensures(Contract.Result<int>() >= 0); return -1; }

Error

Error 1 ''System.Diagnostics.Contracts.ContractException'' is inaccessible due to its protection level.

Editar

Después de reflexionar un poco más, he llegado a la conclusión discutida en los comentarios, así como a lo siguiente. Dado un método, si este tuviera un requisito que pudiera expresarse en el formulario de Contrato de Código, escribiría pruebas como tales.

[TestMethod] [ExpectedException(typeof(ArgumentException))] public void value_input_must_be_greater_than_zero() { // Arrange var person = new Person(); // Act person.Number(-1); }

Esto garantizaría que el contrato sea parte del código y no se eliminará. Sin embargo, esto requeriría que el Contrato del Código arroje la excepción especificada. En algunos casos, esto no sería necesario sin embargo.


Aunque esta pregunta se está haciendo vieja, y ya se ha proporcionado una respuesta, siento que tengo una buena solución que hace que todo sea simple y legible. Al final, nos permite escribir pruebas sobre condiciones previas tan simples como:

[Test] public void Test() { Assert.That(FailingPrecondition, Violates.Precondition); } public void FailingPrecondition() { Contracts.Require(false); }

Bien, entonces la idea es proporcionar el reescritor de contratos de código con una clase de tiempo de ejecución personalizada. Esto se puede configurar en las propiedades del conjunto en "Métodos de reescritura personalizados" (consulte la sección 7.7 del Manual de usuario de contratos de código):

¡Recuerde comprobar también que Call-site Requires Checking !

La clase personalizada se ve así:

public static class TestFailureMethods { public static void Requires(bool condition, string userMessage, string conditionText) { if (!condition) { throw new PreconditionException(userMessage, conditionText); } } public static void Requires<TException>(bool condition, string userMessage, string conditionText) where TException : Exception { if (!condition) { throw new PreconditionException(userMessage, conditionText, typeof(TException)); } } }

Usando una clase PreconditionException personalizada (¡no contiene nada lujoso!). Además, agregamos una pequeña clase de ayuda:

public static class Violates { public static ExactTypeConstraint Precondition => Throws.TypeOf<PreconditionException>(); }

Esto nos permite escribir pruebas simples y legibles sobre violaciones de precondición, como se muestra arriba.


Esto es deliberado, aunque un poco doloroso para las pruebas.

El punto es que en el código de producción nunca deberías atrapar una excepción de contrato; indica un error en su código, por lo que no debe esperar más que excepciones arbitrarias inesperadas que desee capturar en la parte superior de su pila de llamadas para que pueda pasar a la próxima solicitud. Básicamente, no debería ver las excepciones de contrato como aquellas que pueden ser "manejadas" como tales.

Ahora, para las pruebas eso es un dolor ... ¿pero de todos modos quieres probar tus contratos? ¿No es un poco como probar que el compilador te impide pasar una string a un método que tiene un parámetro int ? Usted ha declarado el contrato, puede documentarse adecuadamente y aplicarse de forma adecuada (según la configuración, de todos modos).

Si desea probar excepciones contractuales, puede capturar una Exception en la prueba y verificar su nombre completo, o puede perder el tiempo con el evento Contract.ContractFailed . Esperaría que los marcos de pruebas unitarias tuvieran soporte integrado para esto con el tiempo, pero tomará un poco de tiempo llegar allí. Mientras tanto, es probable que desee tener un método de utilidad para esperar una violación del contrato. Una posible implementación:

const string ContractExceptionName = "System.Diagnostics.Contracts.__ContractsRuntime.ContractException"; public static void ExpectContractFailure(Action action) { try { action(); Assert.Fail("Expected contract failure"); } catch (Exception e) { if (e.GetType().FullName != ContractExceptionName) { throw; } // Correct exception was thrown. Fine. } }


en el vs2010 rtm, el nombre completo ha sido cambiado a "System.Diagnostics.Contracts .__ ContractsRuntime + ContractException". HTH


EDITAR: he tenido una conversión y ya no uso ExpectedException o este atributo a continuación, sino que he codificado algunos métodos de extensión:

AssertEx.Throws<T>(Action action); AssertEx.ThrowsExact<T>(Action action); AssertEx.ContractFailure(Action action);

Estos me permiten ser más preciso sobre dónde se plantea la excepción.

Ejemplo del método ContractFailure:

[SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Cannot catch ContractException")] public static void ContractFailure(Action operation) { try { operation(); } catch (Exception ex) { if (ex.GetType().FullName == "System.Diagnostics.Contracts.__ContractsRuntime+ContractException") return; throw; } Assert.Fail("Operation did not result in a code contract failure"); }

Creé un atributo para MSTest, que se comporta de manera similar a ExpectedExceptionAttribute:

public sealed class ExpectContractFailureAttribute : ExpectedExceptionBaseAttribute { const string ContractExceptionName = "System.Diagnostics.Contracts.__ContractsRuntime+ContractException"; protected override void Verify(Exception exception) { if (exception.GetType().FullName != ContractExceptionName) { base.RethrowIfAssertException(exception); throw new Exception( string.Format( CultureInfo.InvariantCulture, "Test method {0}.{1} threw exception {2}, but contract exception was expected. Exception message: {3}", base.TestContext.FullyQualifiedTestClassName, base.TestContext.TestName, exception.GetType().FullName, exception.Message ) ); } } }

Y esto se puede usar de manera similar:

[TestMethod, ExpectContractFailure] public void Test_Constructor2_NullArg() { IEnumerable arg = null; MyClass mc = new MyClass(arg); }