2011-01-24 11 views
12

Estoy publicando esta pregunta de nuevo a instancias del distinguido Sr. John Skeet, quien me sugirió que diseñe un programa de prueba simple que aísle y demuestre el problema que estoy enfrentando y vuelva a publicar la pregunta. Esta pregunta surgió de this one, así que, por favor, discúlpame si te suena muy familiar. Usted puede obtener detalles adicionales sobre esta pregunta a partir de ese.NUnit: ¿Por qué no Assert.Throws <T> Catch My ArgumentNullException?

El problema que estoy enfrentando se refiere a Assert.Throws<T> de NUnit 2.5.9. Ocasionalmente, no detectará las excepciones lanzadas en el método invocado por TestDelegate. He delimitado este comportamiento de forma reproducible en el siguiente código. . (Aunque esto puede, ciertamente, ser un caso de falla en mi máquina ™

para reproducir el error, he creado una solución con proyectos # DLL dos C:

  • La primera contiene una sola clase, con un único método público. Ese método es un método de extensión que encapsula la lógica necesaria para crear un SqlCommand, rellenar sus parámetros e invocar ExecuteScalar. Este proyecto no incluye otras referencias.
  • El segundo contiene una sola clase con dos métodos que prueba si el método en la primera DLL funciona o no como se esperaba. Este proyecto hace referencia a la primera, e incluye ar eferencia al Marco NUnit. No se hace referencia a otros ensambles.

Cuando camino a través de las pruebas en el depurador, observo lo siguiente:

  1. Assert.Throws invoca correctamente el método ExecuteScalar<T> extensión.
  2. Los valores de los parámetros son nulos, como se esperaba.
  3. ExecuteScalar<T> prueba sus parámetros para valores nulos.
  4. El depurador golpea y ejecuta la línea que contiene throw new ArgumentNullException(...).
  5. Después de ejecutar throw, el control de la aplicación no se transfiere inmediatamente al Assert.Throws. En cambio, continúa en la siguiente línea en ExecuteScalar<T>.
  6. Tan pronto como se ejecuta la siguiente línea de código, el depurador se rompe y muestra el error "Argument null exception no fue manejado por el código de usuario".

El código fuente que aísla este comportamiento se proporciona a continuación.

EL MÉTODO DE EXTENSIÓN

namespace NUnit_Anomaly 
{ 
    using System; 
    using System.Data; 
    using System.Data.SqlClient; 

    public static class Class1 
    { 
     public static T ExecuteScalar<T>(this SqlConnection connection, string sql) 
     { 
      if (connection == null) 
      { 
       throw new ArgumentNullException("connection"); 
      } 

      if (sql == null) 
      { 
       throw new ArgumentNullException("sql"); 
      } 

      using (var command = connection.CreateCommand()) 
      { 
       command.CommandType = CommandType.Text; 
       command.CommandText = sql; 
       return (T)command.ExecuteScalar(); 
      } 
     } 
    } 
} 

los casos de prueba

namespace NUnit_Tests 
{ 
    using System; 
    using System.Data.SqlClient; 
    using System.Diagnostics; 

    using NUnit.Framework; 

    using NUnit_Anomaly; 

    [TestFixture] 
    public class NUnitAnomalyTest 
    { 

     [Test] 
     public void ExecuteDataSetThrowsForNullConnection() 
     { 
      Assert.Throws<ArgumentNullException>(() => ((SqlConnection)null).ExecuteScalar<int>(null)); 
     } 

     [Test] 
     public void ExecuteDataSetThrowsForNullSql() 
     { 

      const string server = "MY-LOCAL-SQL-SERVER"; 
      const string instance = "staging"; 
      string connectionString = String.Format("Data Source={0};Initial Catalog={1};Integrated Security=True;", 
                server, 
                instance); 

      using (var connection = new SqlConnection(connectionString)) 
      { 
       Assert.Throws<ArgumentNullException>(() => connection.ExecuteScalar<int>(null)); 
      } 
     } 
    } 
} 

El efecto neto es que las pruebas fallan cuando no deberían hacerlo. Según mi entender, Assert.Throws<T> debería detectar mi excepción y la prueba debería pasar.

ACTUALIZACIÓN

Seguí el consejo de Hans y comprobó el diálogo Excepciones. No estaba rompiendo en lanzadas excepciones, pero estaba rompiendo en excepciones usuario no administrado. Aparentemente, es por eso que el depurador irrumpe en el IDE cuando se lanza la excepción. Al borrar la casilla de verificación se solucionó el problema y Assert.Throws<T> lo recogió. Sin embargo, si no he hecho esto, no puedo presionar F5 para continuar la ejecución, o la excepción se convertirá en NullReferenceException.

Así que ahora la pregunta es: ¿Puedo configurar saltos de excepción por proyecto? Solo quiero hacer esto cuando estoy probando, pero no en general.

+1

Debug + Exceptions, asegúrese de que las casillas de verificación de Thrown estén desactivadas. –

+0

@ Hans Passant: he verificado que ninguna de las casillas lanzadas está marcada. –

Respuesta

15

Lo que en realidad sucede es que Assert.Throwshace captura su excepción, sin embargo Visual Studio se detiene en la primera oportunidad excepción de todos modos. Puede verificar esto presionando F5; Visual Studio continuará ejecutando felizmente.

Como dice el asistente de excepción, la excepción no se ha manejado por el código de usuario. Así que sabemos que Visual Studio no considera que NUnit sea código de usuario por algún motivo.

enter image description here

Visual Studio realidad te dice esto en texto plano, si usted sabe dónde buscar:

enter image description here

También hay evidencia de este hecho en el seguimiento de pila:

enter image description here

Solución 1: utiliza una compilación de depuración de NUnit con símbolos de depuración. Eso will get Visual Studio to regard NUnit as user code, y así dejar de tratar sus excepciones como "no manejado por el código de usuario". Esto no es trivial, pero podría funcionar mejor a largo plazo.

Solución 2: Desactive la casilla de verificación "Habilitar Sólo mi código" en la configuración de depuración de Visual Studio:

enter image description here

P. S. No estoy considerando alternativas por las que evite el uso de Assert.Throws<T> en total, pero hay formas de hacerlo.

+0

Estoy usando nunit-console.exe y no estoy usando el depurador VS. Ni siquiera estoy ejecutando código de modo de depuración. ¿Esto significa algo si NUnit no está captando mis excepciones? –

+0

@GrantBirchmeier Es posible que tenga un problema diferente, le recomiendo que haga una nueva pregunta y proporcione más detalles allí. –

+0

Resultó que era un error del usuario, todo en mí. –

Cuestiones relacionadas