Come posso simulare / fingere / stub OracleException sigillato senza costruttore pubblico?
-
02-07-2019 - |
Domanda
Nei miei test ho bisogno di testare cosa succede quando viene generata una OracleException (a causa di un errore della procedura memorizzata). Sto cercando di impostare Rhino Mocks su
Expect.Call(....).Throw(new OracleException());
Per qualunque motivo, comunque, OracleException sembra essere sigillata senza alcun costruttore pubblico. Cosa posso fare per testarlo?
Modifica: Ecco esattamente quello che sto cercando di creare un'istanza:
public sealed class OracleException : DbException {
private OracleException(string message, int code) { ...}
}
Soluzione
Sembra che Oracle abbia cambiato i costruttori nelle versioni successive, quindi la soluzione sopra non funzionerà.
Se vuoi solo impostare il codice di errore, il seguente farà il trucco per 2.111.7.20:
ConstructorInfo ci = typeof(OracleException)
.GetConstructor(
BindingFlags.NonPublic | BindingFlags.Instance,
null,
new Type[] { typeof(int) },
null
);
Exception ex = (OracleException)ci.Invoke(new object[] { 3113 });
Altri suggerimenti
Per l'accesso ai dati gestiti di Oracle (v 4.121.1.0) il costruttore è stato nuovamente modificato
var ci = typeof(OracleException).GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance, null, new Type[] { typeof(int), typeof(string), typeof(string), typeof(string) }, null);
var c = (OracleException)ci.Invoke(new object[] { 1234, "", "", "" });
Ecco come lo fai:
ConstructorInfo ci = typeof(OracleException).GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance, null, new Type[] {typeof(string), typeof(int)}, null);
var c = (OracleException)ci.Invoke(new object[] { "some message", 123 });
Grazie a tutto ciò che ti ha aiutato, sei stato votato
Sto utilizzando il client provider di dati Oracle.DataAccess.Client. Ho problemi a costruire una nuova istanza di un oggetto OracleException, ma continua a dirmi che non ci sono costruttori pubblici. Ho provato tutte le idee mostrate sopra e continuo a ricevere un'eccezione di riferimento null.
object[] args = { 1, "Test Message" };
ConstructorInfo ci = typeof(OracleException).GetConstructor(BindingFlags.NonPublic
| BindingFlags.Instance, null, System.Type.GetTypeArray(args), null);
var e = (OracleException)ci.Invoke(args);
Quando eseguo il debug del codice di test, ottengo sempre un valore NULL per 'ci'.
Oracle ha modificato la libreria per non consentire questo? Cosa sto facendo di sbagliato e cosa devo fare per creare un'istanza di un oggetto OracleException da utilizzare con NMock?
A proposito, sto usando la libreria Client per la versione 10g.
Grazie,
Charlie
Usa la riflessione per creare un'istanza di OracleException. Vedi questo post sul blog
Utilizzare la riflessione per creare un'istanza dell'oggetto OracleException? Sostituire
new OracleException()
con
object[] args = ... ;
(OracleException)Activator.CreateInstance(typeof(OracleException), args)
Puoi sempre ottenere tutti i costruttori in questo modo
ConstructorInfo[] all = typeof(OracleException).GetConstructors(
BindingFlags.NonPublic | BindingFlags.Instance);`
Per Oracle.DataAccess
4.112.3.0 questo ha restituito 7 costruttori
Quello che volevo era il secondo nell'elenco che prendeva 5 argomenti, int, string, string, string, int
. Sono rimasto sorpreso dal quinto argomento perché in ILSpy sembrava così
internal OracleException(int errCode, string dataSrc, string procedure, string errMsg)
{
this.m_errors = new OracleErrorCollection();
this.m_errors.Add(new OracleError(errCode, dataSrc, procedure, errMsg));
}
Quindi, per ottenere il costruttore che volevo ho finito con
ConstructorInfo constructorInfo =
typeof(OracleException).GetConstructor(
BindingFlags.NonPublic | BindingFlags.Instance,
null,
new Type[] { typeof(int), typeof(string), typeof(string), typeof(string), typeof(int) },
null);`
Buona soluzione George. Questo funziona anche per SqlException:
ConstructorInfo ci = typeof( SqlErrorCollection ).GetConstructor( BindingFlags.NonPublic | BindingFlags.Instance, null, new Type[] { }, null );
SqlErrorCollection errorCollection = (SqlErrorCollection) ci.Invoke(new object[]{});
ci = typeof( SqlException ).GetConstructor( BindingFlags.NonPublic | BindingFlags.Instance, null, new Type[] { typeof( string ), typeof( SqlErrorCollection ) }, null );
return (SqlException) ci.Invoke( new object[] { "some message", errorCollection } );
-Dave
Puoi scrivere una banale stored procedure che fallisce / errori ogni volta, quindi usarla per testare?