1

Aux fins de tests unitaires, je veux créer un objet fantaisie de type SqlCeLockTimeoutExceptionCréation d'une instance de SqlCeLockTimeoutException

Depuis son constructeur est protégé, j'ai créé une classe étendue dans mon test:

[Serializable] 
private class TestableSqlCeLockTimeoutException : SqlCeLockTimeoutException 
{ 
    public TestableSqlCeLockTimeoutException() 
      : this(new SerializationInfo(typeof (TestableSqlCeLockTimeoutException), 
             new FormatterConverter()), 
        new StreamingContext()) 
    { 
    } 

    protected TestableSqlCeLockTimeoutException(SerializationInfo info, 
               StreamingContext context) 
      : base(info, context) 
    { 
    } 
} 

Cependant , je continue à recevoir l'exception suivante lors de la création d'une instance:

méthode d'essai Foo a jeté exception:
System.Runtime.Serialization.SerializationException: Le membre 'ClassName' est introuvable.

Pourquoi est-ce que je continue à l'obtenir? J'ai essayé de jouer avec l'attribut Serializable en vain.

Toute solution de contournement serait également utile.

Répondre

1

@Mugan vous avez posé une question très intéressante! Pour y répondre, j'ai dû décompiler SqlCeLockTimeoutException. J'ai beaucoup appris quand j'ai essayé de t'aider. Je vous remercie.

Le problème est survenu becouse System.Exception C`tor a besoin de quelques propriétés à désérialisé:

[System.Security.SecuritySafeCritical] // auto-generated 
protected Exception(SerializationInfo info, StreamingContext context) 
{ 
//some validation 
    _className = info.GetString("ClassName"); 
    _message = info.GetString("Message"); 
    _data = (IDictionary)(info.GetValueNoThrow("Data",typeof(IDictionary))); 
    _innerException = (Exception)(info.GetValue("InnerException",typeof(Exception))); 
    _helpURL = info.GetString("HelpURL"); 
    _stackTraceString = info.GetString("StackTraceString"); 
    _remoteStackTraceString = info.GetString("RemoteStackTraceString"); 
    _remoteStackIndex = info.GetInt32("RemoteStackIndex"); 
    _exceptionMethodString = (String)(info.GetValue("ExceptionMethod",typeof(String))); 
    HResult = info.GetInt32("HResult"); 
    _source = info.GetString("Source"); 
//some bla bla.... 

Pour résoudre le problème ci-dessus j'ai changé l'C`tor protégée au public et ensuite l'utiliser:

var info = new SerializationInfo(typeof (TestableSqlCeLockTimeoutException), 
      new FormatterConverter()); 
info.AddValue("ClassName", string.Empty); 
info.AddValue("Message", string.Empty); 
info.AddValue("InnerException", new ArgumentException()); 
info.AddValue("HelpURL", string.Empty); 
info.AddValue("StackTraceString", string.Empty); 
info.AddValue("RemoteStackTraceString", string.Empty); 
info.AddValue("RemoteStackIndex", 0); 
info.AddValue("ExceptionMethod", string.Empty); 
info.AddValue("HResult", 1); 
info.AddValue("Source", string.Empty); 
new TestableSqlCeLockTimeoutException(info,new StreamingContext()); 

Puis nouvelle exception soulevée cette fois de SqlCeException. SqlCeException Ctor a également besoin d'une propriété __Errors__:

protected SqlCeException(SerializationInfo info, StreamingContext context) 
    : base(info, context) 
{ 
    if (info == null) 
    throw new ArgumentNullException("info"); 
    this.Errors = (SqlCeErrorCollection) info.GetValue("__Errors__", typeof (SqlCeErrorCollection)); 
} 

SqlCeErrorCollection Ctor est interne, donc je Reflaction pour créer une instance:

BindingFlags flags = BindingFlags.NonPublic | BindingFlags.Instance; 
CultureInfo culture = null; // use InvariantCulture or other if you prefer 
object instantiatedType = 
     Activator.CreateInstance(typeof(SqlCeErrorCollection), flags, null, null, culture); 
info.AddValue("__Errors__", instantiatedType); 

Maintenant, chaque chose fonctionne. Je finis avec une méthode de création:

private static SqlCeLockTimeoutException CreateSqlCeLockTimeoutExceptionForTest() 
{ 
    var info = new SerializationInfo(typeof (TestableSqlCeLockTimeoutException), 
       new FormatterConverter()); 
    info.AddValue("ClassName", string.Empty); 
    info.AddValue("Message", string.Empty); 
    info.AddValue("InnerException", new ArgumentException()); 
    info.AddValue("HelpURL", string.Empty); 
    info.AddValue("StackTraceString", string.Empty); 
    info.AddValue("RemoteStackTraceString", string.Empty); 
    info.AddValue("RemoteStackIndex", 0); 
    info.AddValue("ExceptionMethod", string.Empty); 
    info.AddValue("HResult", 1); 
    info.AddValue("Source", string.Empty); 
    BindingFlags flags = BindingFlags.NonPublic | BindingFlags.Instance; 
    CultureInfo culture = null; // use InvariantCulture or other if you prefer 
    object instantiatedType = Activator.CreateInstance(typeof (SqlCeErrorCollection), 
           flags, null, null, culture); 
    info.AddValue("__Errors__", instantiatedType); 
    return new TestableSqlCeLockTimeoutException(info, new StreamingContext()); 
} 

une chose que vous pouvez utiliser Reflaction pour créer une nouvelle instance de SqlCeLockTimeoutException au lieu du TestableSqlCeLockTimeoutException:

private static SqlCeLockTimeoutException CreateSqlCeLockTimeoutExceptionForTest() 
{ 
    BindingFlags flags = BindingFlags.NonPublic | BindingFlags.Instance; 
    CultureInfo culture = null; // use InvariantCulture or other if you prefer 
    object instantiatedType = Activator.CreateInstance(typeof (SqlCeErrorCollection), 
        flags, null, null, culture); 

    object result = Activator.CreateInstance(typeof(SqlCeLockTimeoutException), 
        flags, null, new []{instantiatedType}, culture); 

    return (SqlCeLockTimeoutException)result; 
}