2013-06-05 8 views
12

Il blocco precedente che fa riferimento ad un'altra domanda + risposta su SO NON contiene una risposta corretta che si applica qui!È un'eccezione generica supportata all'interno di un fermo?

Ho un metodo utilizzato per il test dell'unità. Lo scopo di questo metodo è garantire che una parte di codice (a cui fa riferimento un delegato) genererà un'eccezione specifica. Se viene lanciata quell'eccezione, il test dell'unità ha esito positivo. Se non viene lanciata alcuna eccezione o viene lanciata un'altra eccezione di tipo, il test dell'unità fallirà.

/// <summary> 
/// Checks to make sure that the action throws a exception of type TException. 
/// </summary> 
/// <typeparam name="TException">The type of exception expected.</typeparam> 
/// <param name="action">The code to execute which is expected to generate the exception.</param> 
public static void Throws<TException>(Action action) 
    where TException : Exception 
{ 
    try 
    { 
     action(); 
    } 
    catch (TException) 
    { 
     return; 
    } 
    catch (Exception ex) 
    { 
     Assert.Fail("Wrong exception was thrown. Exception of type " + ex.GetType() + " was thrown, exception of type " + typeof(TException) + " was expected."); 
    } 
    Assert.Fail("No exception was thrown. Exception of type " + typeof(TException) + " was expected."); 
} 

La chiamata successiva dovrebbe riuscire, ma non riesce:

int result = 0; 
Throws<DivideByZeroException>(() => result = result/result); 

Quando viene generata l'eccezione prevista di tipo TException, è sempre catturato dalla seconda cattura, non per la prima cattura. Perchè è questo?

Ovviamente posso utilizzare un workarround con una cattura e verificare se ex è di tipo TException. Voglio semplicemente sapere/capire perché questo codice viene compilato ma semplice (mai?) Funziona.

EDIT

Su richiesta di un "lavoro" demo:

using System; 

namespace GenericExceptionDemo 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      int n = 0; 
      Catch<DivideByZeroException>(() => n = n/n); 
     } 

     static public void Catch<TException>(Action action) 
      where TException: Exception 
     { 
      try 
      { 
       action(); 
       Console.WriteLine("No exception thrown. !!!Fail!!!"); 
      } 
      catch (TException) 
      { 
       Console.WriteLine("Expected exception thrown. PASS!"); 
      } 
      catch(Exception ex) 
      { 
       Console.WriteLine("An unexpected exception of type " + ex.GetType() + " thrown. !!!FAIL!!!"); 
      } 
     } 
    } 
} 
+7

Quale framework di test dell'unità stai utilizzando? La maggior parte già ha 'Assert.Throws' ... –

+8

Il tuo codice funziona per me ... per favore mostra un programma breve ma completo che mostri il problema. –

+0

Perché affermare che viene lanciato un tipo sbagliato di eccezione? Forse. Lo stesso framework Net ti lancia un System.Drawing.Exception quando lavori con le GUI? –

risposta

2

Tu non sei la prima persona a verificare questo problema. This question è molto simile. Se si analizzano le risposte e i collegamenti, si verifica un errore nel CLR.

EDIT: Come esempio di Martin follow-up, ho eseguito da VS2010 e ottenuto i seguenti risultati:

  • destinati a .NET 4, passaggio
  • destinati a .NET 3.5, FAIL
  • Targeting .NET 3.5 in modalità RELEASE, PASS

Purtroppo tutti i collegamenti SO al Microsoft Bug Report sono morti e non sono riuscito a trovarne altri.

+1

Rispondendo a quella domanda precedente nel 2009, si applica ancora? –

+0

Buona domanda. Ho appena inserito il codice di Martin in VS (con piccole modifiche). Se scelgo come destinazione .NET 4, il codice funziona come previsto. Se scelgo come target 3.5, vedo il comportamento strano descritto da Martin. –

+0

Non si applica. Entrambe le domande sono simili, ma l'altra domanda ha un'eccezione extra 'tex', e la risposta (corretta) è quella di rimuovere quella variabile. Nel mio caso non sto utilizzando una variabile, quindi la risposta non può essere applicata a questa situazione. –

0

(Questa non è una risposta concreta,. Ma non ho potuto pubblicarlo come commento troppo)

non riesco a riprodurre questo (VS 2012, .NET 4.5, C# 5.0, ogni SP installato).

ho definito questa classe eccezione:

class MyException : Exception 
{ 
    public MyException() { } 
    public MyException(string message) : base(message) { } 
} 

e un metodo:

static void Throws<T>(Action action) where T : Exception 
{ 
    try 
    { 
     action(); 
    } 
    catch (T) { Console.WriteLine("got {0}", typeof(T)); } 
    catch (Exception) { Console.WriteLine("got Exception"); } 
} 

e ho testato in questo modo:

Throws<MyException>(() => { throw new MyException(); }); 

int result = 0; 
Throws<DivideByZeroException>(() => result = result/result); 

e l'uscita è:

  • ottenuto Draft.MyException
  • ottenuto Sistema.DivideByZeroException

Quindi (IMHO) dovresti cercare altrove.

Problemi correlati