2009-06-27 20 views
11

Voglio testare la mia parte di codice che restituisce la domanda di password degli utenti. Quindi ho creato un mockup del provider di appartenenza usando Moq.Come faccio a configurarlo (Configurazione Moq)

Non penso di aver bisogno di mostrarti il ​​codice attuale solo la parte di test.

// Arrange 
var membershipMock = new Mock<MembershipProvider>(); 
membershipMock.Setup(m => m.GetUser("test", false).PasswordQuestion).Returns("Password"); 
authentication.Authenticate.Provider = membershipMock.Object; 

// Act 
var actual = authentication.PasswordRecoveryStep1(It.IsAny<string>()); 

// Assert 
Assert.That(actual, Is.EqualTo("Password")); 

Così, quando ho eseguito questo in Nunit ottengo questo:

Test.Controllers.AuthenticationControllerTest.Test_If_Password_Recovery_Setp1_Returns_Users_PasswordQuestion: 
System.NotSupportedException : Only property accesses are supported in intermediate invocations on a setup. Unsupported expression m.GetUser("test", False). 

at Moq.Mock.AutoMockPropertiesVisitor.VisitMethodCall(MethodCallExpression m) 
at Moq.ExpressionVisitor.Visit(Expression exp) 
at Moq.Mock.AutoMockPropertiesVisitor.VisitMemberAccess(MemberExpression m) 
at Moq.ExpressionVisitor.Visit(Expression exp) 
at Moq.Mock.AutoMockPropertiesVisitor.SetupMocks(Expression expression) 
at Moq.Mock.GetInterceptor(LambdaExpression lambda, Mock mock) 
at Moq.Mock.<>c__DisplayClass15`2.<SetupGet>b__14() 
at Moq.PexProtector.Invoke[T](Func`1 function) 
at Moq.Mock.SetupGet[T1,TProperty](Mock mock, Expression`1 expression) 
at Moq.Mock.<>c__DisplayClass12`2.<Setup>b__11() 
at Moq.PexProtector.Invoke[T](Func`1 function) 
at Moq.Mock.Setup[T1,TResult](Mock mock, Expression`1 expression) 
at Moq.Mock`1.Setup[TResult](Expression`1 expression) 
at Test.Controllers.AuthenticationControllerTest.Test_If_Password_Recovery_Setp1_Returns_Users_PasswordQuestion() in D:\MvcApplication9\Test\Controllers\AuthenticationControllerTest.cs:line 186 

Così sto indovinando che è qualcosa a causa della proprietà che sto cercando di accesso. Non sono sicuro di come configurarlo. Non sono molto bravo con lambda (e non sono ancora riuscito a trovare un tutorial su di loro) quindi non sono sicuro di poterlo organizzare in modo diverso per farlo funzionare.

Oppure se mi mancava il marchio.

risposta

13

La risposta è nel messaggio di eccezione:

... accessi di proprietà sono supportati solo in invocazioni intermedie su una messa a punto ...

Prova questa:

var user = new Mock<MemberShipUser>(); 
user.SetupGet(x => x.PasswordQuestion).Returns("Password"); 

membershipMock.Setup(m => m.GetUser("test", false)).Returns(user.Object); 
+1

Ya non ero sicuro di cosa fosse quel 100%. Significa solo proprietà di primo livello? Anche quello che hai superato quell'errore ma qualcos'altro è sbagliato. Sembra che non stia usando l'oggetto mock e tenta di eseguirlo effettivamente contro il database. L'ho configurato come sempre e ho aggiunto l'oggetto fittizio che deve essere utilizzato da questa linea: authentication.Authenticate.Provider = membershipMock.Object; – chobo2

+0

Ok, l'ho capito. Ho completamente dimenticato quando ho scritto questa roba che ho usato cose come Membership.GetUser(); Quindi non è mai stato usando la mia proprietà che ottiene un vero fornitore o il provider di mockup. Quindi funziona ora. Tuttavia non capisco quale sia la differenza tra questi anche: Membership.GetUser(); // quello che stavo usando prima. da quando lo sto passando nella cosa del provider (poiché penso che se non l'avessi non sarei in grado di realizzare l'oggetto fittizio? Come potrei usare solo l'abbonamento invece di Membership.Provider?) Mi sembra di ottenere uno diverso. sembra lo stesso (chiamato getUser) ma solo – chobo2

+0

ha come 2 metodi di sovraccarico. Dove come il primo ha come 6. – chobo2

2

Suppongo che l'invocazione intermedia a cui fa riferimento sia questa: m.GetUser("test", false) poiché è seguita da .PasswordQuestion. Quello che dice è: non puoi avere un metodo usato come stub intermedio, solo una proprietà. Questo particolare framework sembra supportare stub intermedi (cioè costruisce X.Y nella definizione stub, nota il punto) ma molti altri no.

I tronconi non sono magici, tutto ciò che possono fare è intercettare le chiamate e sostituire il risultato restituito con il valore fornito. Nel tuo caso, il tuo stub di GetUser deve restituire un simulato utente, con la sua PasswordQuestion cancellata per restituire "Password".

Un altro problema con il codice è che stai prendendo in giro MembershipProvider direttamente. Il modo in cui la maggior parte del framework di derisione funziona, se prendi in giro un'interfaccia, generano dinamicamente una classe che la implementa e quando prendi in giro una classe, generano una classe che eredita da essa e sostituisce qualsiasi metodo virtuale. Tuttavia, se il metodo non è virtuale, non può sovrascriverlo, quindi il comportamento misto che potresti osservare. Ti suggerisco di vedere se c'è un'interfaccia come IMembershipProvider e se sì, usala nel tuo codice invece della classe concreta.

+0

Questo è quello che sembra essere il codice eu-ge-ne ma continua a provare ma sembra che stia cercando di usare il mio database. – chobo2

+0

@ chobo2, ho aggiornato la risposta. non dimenticare di upvote :) – zvolkov

+0

MembershipProvider.GetUser() è un metodo astratto; MembershipUser.PasswordQuestion è una proprietà virtuale –

Problemi correlati