2010-03-29 13 views
14

Mam funkcję Chcę mieć Moq. Problem polega na tym, że wymaga 5 parametrów. Framework zawiera tylko Action<T1,T2,T3,T4> i generycznyMoqa tylko przeciąża Action i cztery generyczne wersje. Czy istnieje elegancki sposób na obejście tego problemu?Moq funkcja z 5+ parametrami i argumentami wywoływania dostępu

To jest to, co chcę zrobić:

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 nie zezwala na to, bo nie ma generic Action że trwa 5+ parametry. Uciekłem, robiąc własny odcinek. Oczywiście, lepiej byłoby użyć Moq z wszystkimi jego weryfikacjami, itp.

+0

Prawdopodobnie nie zamierzam ci pomóc, ale w usłudze .NET 4.0 akcja może zająć do 16 parametrów! – RichardOD

+1

Nawet jeśli byłeś w .NET 4.0, Moq wciąż obsługuje maksymalnie 4 parametry w swojej najnowszej wersji beta. Aby to naprawić, musisz pobrać źródło i wykonać własne. –

+1

Możesz użyć metody rozszerzenia – Thomas

Odpowiedz

3

Wiem, że to prawdopodobnie psuje twój projekt, ale przy tak wielu parametrach nie byłoby lepiej przekazać tablicę parametrów?

+0

+1, chociaż obiekt parametru może być lepszy, jeśli argumenty reprezentują różne koncepcje –

+0

Jak wspomniałeś w następnej odpowiedzi, musiałbym zmienić sam Moq, ponieważ nie pozwala na to przeciążenie . Niezależnie od tego, potrzebuję generycznych, aby uzyskać dostęp do parametrów wywołania. – beerncircus

+1

W rzeczywistości, jak zaznacza Mark, lepszym rozwiązaniem jest przekazanie obiektu zawierającego wszystkie potrzebne parametry. Oczywiście to zmieni sposób, w jaki wyśmiewasz to. –

-1

To jest całkiem proste. Po prostu zdefiniuj swój własny Action<T1, T2, T3, T4, T5> i jesteś gotowy.

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

To wszystko, Action, Action<T>, ... Action<T1, T2, T3, T4> są określone tak jak w ramach. Nic więcej. Prosty!

+3

Nadal będziesz musiał zmodyfikować kod źródłowy Moq, aby obsługiwał więcej niż cztery parametry w wywołaniu zwrotnym. –

+0

@ "Robert Harvey" - Tak, masz rację. Przeoczyłem to. Być może Currying może być przydatny? – Enigmativity

+0

Zmienianie Moq przeciąża, aby wykonać Czynność z 5+ parametrami jest jedynym rozwiązaniem, które widzę. Co masz na myśli mówiąc "currying"? – beerncircus

3

Użyj metody rozszerzenia, aby rozszerzyć strukturę moq, jeśli nie chcesz modyfikować źródła.

//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

Co następnie?Nadal muszę napisać własną metodę, która nie jest wcale łatwiejsza niż modyfikowanie kodu źródłowego. – beerncircus

+0

Zaktualizowałem przykład mojego kodu, aby podać prosty przykład. Wszystko, co robisz, to rozszerzenie interfejsu ICallback, który jest częścią struktury moq. Czy znasz metody tworzenia rozszerzeń? – Thomas

+1

Twoja metoda rozszerzenia w rzeczywistości nic nie robi, więc jak by to działało, poza tym, że nie narzeka kompilator? –

16

ta jest obsługiwana w ostatnim wydaniu Min 4,0 (4.0.10827), który został wydany w dniu 12 kwietnia 2011. Jeśli używasz .NET 4, będzie można wyśmiewać się do 16 parametrów.

+1

To zdecydowanie najlepsza odpowiedź ... –

4

Wiem, że to stary post, ale myślałem, że ten kod może pomóc innym osobom mającym ten problem ze starszą wersją Moq. Oto przykład z 5 i 6 argumentami, który można rozszerzyć na obsługę dowolnej liczby.

Testowałem to w wersji 3.1.0.0, ale powinno również działać z innymi wersjami.

Sekretem jest użycie refleksji dostępu „SetCallbackWithArguments” chronionej metoda na podstawowej klasy ...

nadzieję, że to przydatne dla kogoś!

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 }); 
    } 
} 
Powiązane problemy