2013-03-12 9 views
7

Questo codice:Moq It.Is <> non corrispondenza

hub.MockedUserRepository.Setup(r => r.Update(It.IsAny<ControllUser>())) 
         .Callback((ControllUser usr) => Console.WriteLine("NULL = " + (usr.Zombies[0].ConnectionId == null))) 
         .Verifiable(); 

stamperà

NULL = True

Così sto pensando di utilizzare questo abbinamento si catturarlo:

var zombieDisconnectParameterMatcher = It.Is<ControllUser>(x => x.Zombies[0].ConnectionId == null); 
hub.MockedUserRepository.Setup(r => r.Update(zombieDisconnectParameterMatcher)) 
         .Callback((ControllUser usr) => Console.WriteLine("NULL = " + (usr.Zombies[0].ConnectionId == null))) 
         .Verifiable(); 

Ma non lo fa .

Perché?

risposta

9

Osservando lo source code of It, ha a che fare con gli alberi di espressione. Mi piace la domanda; possono essere piuttosto sconcertanti. Se volete dare un'occhiata alle seguenti definizioni dei metodi:

public static TValue It.Is<TValue>(Expression<Func<TValue, bool>> match) 
{ 
     return Match<TValue>.Create(
       value => match.Compile().Invoke(value), 
       () => It.Is<TValue>(match)); 
} 

public static T Match.Create<T>(Predicate<T> condition, Expression<Func<T>> renderExpression) 
{ 
     // ... 
     return default(T); 
} 

Se si desidera eseguire la seguente riga:

var zombieDisconnectParameterMatcher = It.Is<ControllUser>(x => x.Zombies[0].ConnectionId == null); 

Poi It.Is<ControllUser>() cercherà di chiamare un metodo chiamato Match.Create<ControllUser>(), che restituisce il valore predefinito di ControllUser. Presumo che ControllUser sia una classe e pertanto zombieDisconnectParameterMatcher sarà null. Dovresti essere in grado di vederlo con il debugger. Quindi, quello che in realtà si sta chiamando è:

hub.MockedUserRepository.Setup(r => r.Update(null)) 
    .Callback((ControllUser usr) => Console.WriteLine("NULL = " + (usr.Zombies[0].ConnectionId == null))) 
    .Verifiable(); 

Quando si esegue il metodo Update con un non-null ControllUser (dal metodo che è in fase di test, per esempio), la richiamata non si innescherà. Semplicemente non corrisponde ai criteri poiché non è nulla. Vedresti che anche la verifica fallisce.

Per risolvere questo problema, allineare la variabile zombieDisconnectParameterMatcher o trasformarla in una variabile di tipo expression (ad esempio). Quest'ultimo farà in modo che il codice non venga eseguito, ma trattato come un'espressione a cui il framework mock può ragionare ('è Zombies[0].ConnectionId == null chiamato con Zombies[0].ConnectionId == null?).

+0

Mi inchino in segno di riverenza a voi, signore @ Caramiriel. – fernandoespinosa

1

Dipende come viene istanziata l'istanza ControllUser. Se l'istanza a cui si fa riferimento all'interno della simulazione non è l'istanza effettiva a cui si fa riferimento nel codice in prova, Setup avrà esito negativo. È necessario assicurarsi che l'istanza di ControllUser a cui si fa riferimento nel codice in prova sia lo stesso oggetto come quello nel codice di prova. In caso contrario, dovrai testarlo utilizzando It.IsAny<ControllUser>() e una richiamata, come mostra il tuo primo esempio. È difficile dire con certezza senza vedere altro del codice che stai testando.