2012-10-18 4 views
82

Data la seguente interfaccia:Come si esegue il Moq di un metodo con un argomento facoltativo nella sua firma senza specificarlo esplicitamente o utilizzando un sovraccarico?

public interface IFoo 
{ 
    bool Foo(string a, bool b = false); 
} 

tentativo di prendere in giro usando Moq:

var mock = new Mock<IFoo>(); 
mock.Setup(mock => mock.Foo(It.IsAny<string>())).Returns(false); 

dà il seguente errore in fase di compilazione:

Un albero di espressione non può contenere una chiamata o invocazione che utilizza argomenti facoltativi

Ho trovato il problema sopra sollevato come enhancement nell'elenco di problemi di Moq e sembra essere assegnato alla versione 4.5 (ogni volta che è).

La mia domanda è: cosa devo fare dato che quanto sopra non verrà corretto in qualsiasi momento presto? Le mie opzioni sono solo per impostare esplicitamente il valore predefinito del parametro opzionale ogni volta che lo schernisco (che tipo di sconfigge il punto di specificarne uno in primo luogo) o per creare un sovraccarico senza il bool (come quello che avrei fatto prima del C# 4)?

O qualcuno ha trovato un modo più intelligente per superare questo problema?

+4

sarebbe ragionevole specificare solo It.IsAny () per il secondo parametro? –

+0

Un anno e mezzo dopo è ancora vero .. – Mukus

risposta

63

credo che l'unica scelta in questo momento è quello di includere esplicitamente il parametro bool nel setup per Foo.

Non credo che vanifichino lo scopo di specificare un valore predefinito. Il valore predefinito è utile per chiamare il codice, ma penso che dovresti essere esplicito nei test. Supponiamo che tu possa omettere di specificare il parametro bool. Cosa succede se, in futuro, qualcuno cambia il valore predefinito di b in true? Ciò porterà a test falliti (e giustamente), ma saranno più difficili da risolvere a causa del presupposto nascosto che b è false. La specifica esplicita del parametro bool ha un altro vantaggio: migliora la leggibilità dei test. Qualcuno che li segue saprà presto che esiste una funzione che accetta due parametri. Questo è il mio 2 centesimi, almeno :)

Come per specificarlo ogni volta che lo prendi in giro, non duplicare il codice: crea e/o inizializza il mock in una funzione, in modo da avere un solo punto di cambiamento . Se davvero si vuole, si può superare di Moq apparente a breve venire qui duplicando Foo 's parametri in questa funzione di inizializzazione:

public void InitFooFuncOnFooMock(Mock<IFoo> fooMock, string a, bool b = false) 
{ 
    if(!b) 
    { 
     fooMock.Setup(mock => mock.Foo(a, b)).Returns(false); 
    } 
    else 
    { 
     ... 
    } 
} 
+1

Ottima risposta; Sono già andato avanti e l'ho specificato esplicitamente nel mio mock ma la tua risposta conferma in modo molto chiaro e logico perché dovrei farlo in questo modo. Grazie, @ Chris. – Appulus

+7

cambiando un parametro predefinito "dovrebbe" interrompere i test. Il mancato test fallisce quando un valore predefinito viene modificato può essere un segno di test errati. Il codice potrebbe utilizzare i valori predefiniti ma i test no? –

+0

Un po 'di tempo, ma ho provato questo approccio con Moq quando provo a simulare un'interfaccia (IDConnection in Dapper) e sto ancora ricevendo lo stesso errore. Qualche idea, perché? Esempio di riga: mockDB.Setup (x => x.Query (It.IsAny (), It.IsAny (), It.IsAny (), false, 600)). Returns (new List ()); Gli ultimi due valori sono i parametri opzionali sul metodo che sto configurando. – Raelshark

5

appena incontrato questo problema oggi, Moq non supporta questo caso d'uso. Quindi, sembra che l'override del metodo sarebbe sufficiente per questo caso.

public interface IFoo 
{ 
    bool Foo(string a); 

    bool Foo(string a, bool b); 
} 

Ora entrambi i metodi sono disponibili e questo esempio avrebbe funzionato:

var mock = new Mock<IFoo>(); 
mock.Setup(mock => mock.Foo(It.IsAny<string>())).Returns(false);