2010-03-29 6 views
14

Ho una funzione che desidero Moq. Il problema è che ci vogliono 5 parametri. Il framework contiene solo Action<T1,T2,T3,T4> e il generico di Moq CallBack() solo overload Action e le quattro versioni generiche. C'è una soluzione elegante per questo?Moq una funzione con 5+ parametri e argomenti di chiamata di accesso

Questo è quello che voglio fare:

public class Filter : IFilter 
{ 
    public int Filter(int i1, int i2, int i3, int i4, int i5){return 0;} 
} 

//Moq code: 
var mocker = new Mock<IFilter>(); 
mocker.Setup(x => x.Filter( 
    It.IsAny<int>(), 
    It.IsAny<int>(), 
    It.IsAny<int>(), 
    It.IsAny<int>(), 
    It.IsAny<int>(), 
    It.IsAny<int>()) 
.Callback 
( 
    (int i1, int i2, int i3, int i4, int i5) => i1 * 2 
); 

Moq non permette questo, perché non v'è alcuna azione generico che prende 5+ parametri. Ho fatto ricorso al mio stub. Ovviamente, sarebbe meglio usare Moq con tutte le sue verifiche, ecc.

+0

Probabilmente non ti aiuterà, ma in .NET 4.0 L'azione può richiedere fino a 16 parametri! – RichardOD

+1

Anche se si era in .NET 4.0, Moq supporta ancora solo un massimo di 4 parametri nella sua ultima versione beta. Per risolverlo, dovresti scaricare il codice sorgente e caricare il tuo. –

+1

È possibile utilizzare un metodo di estensione – Thomas

risposta

3

So che questo probabilmente rompe il tuo progetto, ma con molti parametri non sarebbe meglio passare un array param?

+0

+1, anche se un oggetto parametro potrebbe essere migliore se gli argomenti rappresentano concetti diversi –

+0

Come accennato alla prossima risposta, avrei bisogno di modificare Moq stesso poiché non consente questo sovraccarico . Indipendentemente da ciò, ho bisogno di generici in modo da poter accedere ai parametri di chiamata. – beerncircus

+1

In realtà, come sottolinea Mark, una soluzione migliore è passare un oggetto contenente tutti i parametri necessari. Certo, questo cambierà il tuo modo di deriderlo. –

-1

Questo è in realtà abbastanza semplice. Basta definire il tuo Action<T1, T2, T3, T4, T5> e sei a posto.

public delegate void Action<T1, T2, T3, T4, T5>(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5); 

Questo è tutto ciò che il Action, Action<T>, ..., Action<T1, T2, T3, T4> sono definiti come nel quadro. Niente di più. Semplice!

+3

Dovreste ancora modificare il codice sorgente Moq per supportare più di quattro parametri in un callback. –

+0

@ "Robert Harvey" - Sì, hai ragione. L'ho trascurato. Forse Currying potrebbe essere utile? – Enigmativity

+0

Cambiare i sovraccarichi Moq per eseguire un'azione di 5+ parametri è l'unica soluzione che vedo. Cosa intendi con "curring"? – beerncircus

3

Utilizzare un metodo di estensione per estendere il framework moq se non si desidera modificare l'origine.

//Extension Method 

    public static class MoqExtensions 
    { 
     public static void Callback<T1, T2, T3, T4, T5>(this ICallback iCallBack, Action<T1, T2, T3, T4, T5> action) 
     { 
     } 
    } 

//Your class and interface 

     public interface IMyClass 
     { 
      void Method(string arg1, string arg2, string arg3, string arg4, string arg5); 
     } 

     public class MyClass : IMyClass 
     { 
      public void Method(string arg1, string arg2, string arg3, string arg4, string arg5) 
      { 
       //Do something 
      } 
     } 

//Your test 

     [TestMethod] 
     public void ExampleTest() 
     { 
      Mock<IMyClass> mockMyClass = new Mock<IMyClass>(); 
      mockMyClass.Setup(s => s.Method(It.IsAny<string>(), 
              It.IsAny<string>(), 
              It.IsAny<string>(), 
              It.IsAny<string>(), 
              It.IsAny<string>())) 
       .Callback<string, string, string, string, string>((string arg1, string arg2, string arg3, string arg4, string arg5) 
        => { /* Run your mock here */ }); 
     } 
+0

E poi?Devo ancora scrivere il mio metodo, che non è più semplice della modifica del codice sorgente. – beerncircus

+0

Ho aggiornato il mio esempio di codice per dare un semplice esempio. Tutto quello che stai facendo è l'estensione dell'interfaccia ICallback che fa parte del framework moq. Hai familiarità con la creazione di metodi di estensione? – Thomas

+1

Il tuo metodo di estensione in realtà non fa nulla, quindi come funziona, oltre a non far lamentare il compilatore? –

16

Questo è supportato nella versione finale di Moq 4.0 (4.0.10827), che è stato rilasciato il 12 aprile 2011. Se si sta utilizzando .NET 4, sarete in grado di prendere in giro fino a 16 parametri.

+1

Questa è di gran lunga la migliore risposta ... –

4

So che questo è un vecchio post, ma ho pensato che questo codice potrebbe aiutare altri utenti che hanno questo problema con una versione precedente di Moq. Ecco un esempio con 5 e 6 argomenti e può essere esteso per supportare qualsiasi numero.

Ho provato questo con la versione 3.1.0.0, ma dovrebbe funzionare anche con altre versioni.

Il segreto è quello di utilizzare la reflection per accedere 'SetCallbackWithArguments' il metodo protetto sulla classe sottostante ...

Spero che questo è utile a qualcuno!

public delegate void Action<T1, T2, T3, T4, T5>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5); 
public delegate void Action<T1, T2, T3, T4, T5, T6>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6); 

public static class MoqExtensions 
{ 
    public static ICallbackResult Callback<T1, T2, T3, T4, T5>(this ICallback call, Action<T1, T2, T3, T4, T5> callback) 
    { 
     call.SetCallbackWithArguments(callback); 
     return (ICallbackResult)call; 
    } 

    public static ICallbackResult Callback<T1, T2, T3, T4, T5, T6>(this ICallback call, Action<T1, T2, T3, T4, T5, T6> callback) 
    { 
     call.SetCallbackWithArguments(callback); 
     return (ICallbackResult)call; 
    } 

    public static void SetCallbackWithArguments(this ICallback call, Delegate callback) 
    { 
     MethodInfo methodInfo = call.GetType().GetMethod("SetCallbackWithArguments", BindingFlags.NonPublic | BindingFlags.Instance); 
     methodInfo.Invoke(call, new object[] { callback }); 
    } 
}