2013-07-25 13 views
5

Sto lavorando su alcuni automatismi di test per un servizio e ho trovato un modo semplice per implementare alcune verifiche di configurazione comuni & in una 'sessione'.Come posso verificare se sono già state lanciate delle eccezioni?

Concettualmente, un banco di prova potrebbe essere simile a questo:

using (var managerSession = new Session(managerRole)) 
{ 
    // A manager puts some items in warehouse 
} 

using (var employeeSession = new Session(employeeRole)) 
{ 
    // An employee moves items from warehouse to store 
} 

using (var customerSession = new Session(customerRole)) 
{ 
    // A customer can buy items from the store 
} 

Nel costruttore dell'oggetto Session ho creato un collegamento al servizio sto testando con l'autenticazione corretta per il ruolo, ecc, e nella sessione di Dispose() metodo Ho un blocco di convalida comune che, ad esempio, controlla che nessun errore o avviso sul lato server sia stato sollevato durante la durata della sessione.

Ora, ovviamente, si tratta di un tipo di abuso del pattern IDispose e se il codice di test all'interno di un blocco utilizza genera un'eccezione E anche il blocco di validazione genera un'eccezione, mentre la seconda eccezione maschera il primo.

Concettualmente, se abbiamo questo scenario:

using (var managerSession = new Session(managerRole)) 
{ 
    Assert.IsTrue(managerSession.DoJob(), "Manager did not do his job"); 
} 

... e l'asserzione non riesce o la chiamata a managerSession.DoJob() genera un'eccezione, quindi vorrei il metodo Session Dispose() per saltare il blocco di validazione, cioè

public void Dispose() 
{ 
    if (NoExceptionThrown()) 
    { 
     Assert.IsFalse(this.serviceConnection.HasErrors(), "Service connection has errors"); 
    } 

    this.serviceConnection.Dispose(); 
} 

... in modo tale che il metodo di prova non manca mai con 'Raccordo di servizio ha errori' se non riesce in realtà con 'direttore non fare il suo lavoro'

La mia domanda è: è possibile implementare il metodo 'NoExceptionThrown()' qui? Esiste qualche proprietà globale che può essere verificata o qualcosa di nascosto in Thread.CurrentThread che potrebbe essere utilizzato?

Aggiornamento:

La mia domanda è non come il refactoring questo :-)

potrei ovviamente utilizzare questo modello invece:

Session.ForRole(managerRole, (session) => { /* Test code here */ }); 

Con il metodo statico ForRole() definito come

public static void ForRole(Role r, Action<Session> code) 
{ 
    var session = new Session(r); 
    try 
    { 
     code(session); 
     Assert.IsFalse(session.serviceConnection.HasErrors()); 
    } 
    finally 
    { 
     session.Dispose(); 
    } 
} 

Ma sono curioso di sapere se esiste un modo per afferrare lo stato di eccezione come descritto sopra.

+2

Due cose. Innanzitutto, sì, questo è un abuso di "IDisposable". Usa 'IDisposable' per significare" Possiedo una risorsa non gestita che dovrebbe essere liberata il prima possibile ". Farlo significa qualcos'altro rende il tuo codice difficile da leggere. In secondo luogo, sei preoccupato per * qualsiasi * eccezione, o solo * eccezioni non rilevate? Supponiamo che il codice di test generi un'eccezione, lo intercetta e si completi normalmente. Dovrebbe essere contrassegnato? –

+0

Ah, sono solo preoccupato per le eccezioni _uncaught_. Aggiornerò la domanda ... – Christoffer

+0

Per quanto riguarda l'abuso di IDisposable: in realtà sono più preoccupato di perdere la convalida comune per ogni sessione piuttosto che il potenziale mascheramento degli errori, quindi questa domanda è più di una funzionalità "bella da avere". I blocchi effettivi del codice di test sono 10-100 linee di codice di automazione dell'interfaccia utente e abbiamo già individuato i difetti non rilevati perché uno dei passaggi di convalida è stato perso in uno dei blocchi (o riportato nel blocco errato). – Christoffer

risposta

1

Sarebbe stato utile se ci fosse un sovraccarico di IDisposable.Dispose che ha avuto un parametro di tipo Exception per indicare ciò che fa eccezione, se del caso, era in corso in un contesto finally connessi alla sua pulizia.Mentre un metodo Dispose generalmente non dovrebbe preoccuparsi dei particolari dell'eccezione, possono verificarsi delle condizioni durante il metodo Dispose che dovrebbe essere segnalato al chiamante. Qualsiasi eccezione generata da Dispose sostituirà qualsiasi eccezione che era in sospeso nel contesto finally del chiamante, quindi sarebbe utile se un metodo Dispose incapsulasse un'eccezione in sospeso prima di sostituirlo. Sfortunatamente, nessuna di queste funzionalità esiste e non mi aspetto di essere aggiunta.

Mentre ci sono alcuni hack che possono essere utilizzati per ottenere qualcosa come l'effetto desiderato, l'unico metodo semanticamente corretto è che l'eccezione sia un parametro per un metodo Dispose. Il problema con qualsiasi altro approccio è che un Dispose può essere eseguito da più blocchi nidificati finally, alcuni dei quali hanno eccezioni in sospeso e altre no; il codice che esamina il contesto di esecuzione per determinare lo stato del blocco finally più profondamente annidato potrebbe non riuscire se tale blocco non è quello che protegge la durata dell'oggetto da smaltire.

+0

Penso che accetterò questa risposta come la più corretta – Christoffer

0

Beh, un modo sicuro, ma brutto, è di avere un bool (predefinito falso) sulla classe.

using (var managerSession = new Session(managerRole)) 
{ 
    Assert.IsTrue(managerSession.DoJob(), "Manager did not do his job"); 
    managerSession.NoExceptionThrown = true; 
} 

Non credo che otterrete molto più pulito di quello con il vostro modello IDisposable.

In questo caso, un try ... catch ... infine può funzionare meglio in quanto si avrà accesso diretto all'oggetto di eccezione, che è possibile verificare per nullità (è una parola?) Ed eventualmente persino conservarlo per un uso successivo. Non dovresti perdere nulla, perché using è solo zucchero per un tentativo di cattura finalmente.

+1

Sì, nullità è una parola perfettamente cromatica. – Christoffer

+0

E per un'osservazione più seria, l'impostazione di una proprietà che controlla il blocco di validazione nel metodo Dispose non è in realtà una buona idea. Se aggiungiamo qualcosa su ogni blocco di utilizzo in ogni caso, allora sarebbe meglio rifattorizzare il codice di validazione esistente in un metodo separato e chiamarlo appena prima di chiudere l'ambito – Christoffer

+0

@Christoffer Sì, penso che stai provando a fare un round-plug-in-a-foro-quadrato cosa con l'utilizzo. Come ha sottolineato il supercat, il modo corretto è passare l'oggetto di eccezione o un'indicazione di se si è verificata un'eccezione. Quindi, suppongo che potresti aggiungere il metodo appropriato, abbandonare l'utilizzo e chiamare Dispose (eccezione) te stesso? Ci sono anche problemi, e non penso che sarete in grado di forzare la lingua a fare esattamente ciò che vorreste senza sventrare e riattaccare la testa all'indietro: c. E per quanto ne so, non c'è modo di verificare eventuali eccezioni al di fuori di un blocco catch. – Xcelled194

Problemi correlati