2009-06-27 11 views
11

Chcę przetestować część kodu, która zwraca pytanie o hasło użytkownika. Zrobiłem więc makietę dostawcy członkostwa za pomocą Moq.Jak to skonfigurować (konfiguracja Moq)?

Nie sądzę, żebym musiał pokazać wam rzeczywisty kod, tylko jego część testową.

// 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")); 

Więc kiedy biegnę to w NUnit uzyskać to:

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 

Więc jestem zgadywania to jest coś, z powodu tej własności, że próbuję dostępu. Nie wiem, jak to skonfigurować. Nie jestem zbyt dobry z lambdami (i nie udało mi się jeszcze znaleźć ich tutoriala), więc nie jestem pewien, czy mógłbym jakoś inaczej zorganizować to, by działało.

Albo, jeśli całkowicie przegapiłem znak.

Odpowiedz

13

Odpowiedź jest w wiadomości wyjątek:

... Tylko dostępy własności są obsługiwane w pośrednich wezwań na setup ...

Spróbuj tego:

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

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

Nie byłem pewien, co to 100%. Czy to znaczy tylko właściwości pierwszego poziomu? Również to, co przeszedłeś przez ten błąd, ale coś innego jest nie tak. Wygląda na to, że nie używa on symulowanego obiektu i próbuje go uruchomić względem bazy danych. Mam to ustawienie w taki sam sposób jak zawsze i dodałem obiekt próbny do użycia przez tę linię: authentication.Authenticate.Provider = membershipMock.Object; – chobo2

+0

Ok, wymyśliłem to. Całkowicie zapomniałem, kiedy pisałem te rzeczy, używałem rzeczy takich jak Membership.GetUser(); Więc nigdy nie korzystałem z mojej nieruchomości, która dostała prawdziwego dostawcę lub dostawcę makiety. Teraz to działa. Nie rozumiem jednak, jaka jest między nimi różnica: Członkostwo.GetUser(); // co wcześniej używałem. teraz, ponieważ przekazuję to w rzeczy dostawcy (ponieważ myślę, że gdybym nie zrobił, nie byłbym w stanie zrobić fałszywego obiektu? Jakbym mógł po prostu użyć członkostwa zamiast członkostwa.Provider?) Wydaje mi się, że dostaję inny. wygląda tak samo (zwany getUser), ale tylko – chobo2

+0

ma 2 metody przeciążania. Gdzie jest ten pierwszy 6. – chobo2

2

Przypuszczam, że pośrednia inwokacja, do której się odnosi, jest następująca: m.GetUser("test", false), po której następuje .PasswordQuestion. To, co mówi, brzmi: nie można zastosować metody jako pośredniego kodu pośredniczącego, a jedynie właściwość. Ten konkretny framework wydaje się obsługiwać pośrednie kody pośredniczące (to znaczy konstruuje X.Y w definicji stub, należy zwrócić uwagę na kropkę), ale większość innych nie.

Skróty nie są magiczne, jedyne, co mogą zrobić, to przechwycić połączenia i zastąpić zwracany wynik z podaną wartością. W twoim przypadku, twój stub z GetUser musi zwrócić , a następnie udawać użytkownika o nazwie użytkownika, z hasłem PasswordQuestion oddalonym o "Hasło".

Kolejnym problemem związanym z Twoim kodem jest to, że kpisz bezpośrednio z programu MembershipProvider. W większości przypadków szydercza struktura działa, gdy kpisz z interfejsu, dynamicznie generuje klasę, która ją implementuje, a kiedy kpisz z klasy, generuje klasę, która dziedziczy po niej i zastępuje wszelkie wirtualne metody. Jednakże, jeśli metoda nie jest wirtualna, nie może jej zastąpić, stąd mieszane zachowanie, które można zaobserwować. Proponuję sprawdzić, czy istnieje interfejs taki jak IMembershipProvider, a jeśli tak, użyj go w swoim kodzie zamiast konkretnej klasy.

+0

Tak wygląda kod eu-ge-ne, ale wciąż próbuje, ale wygląda na to, że próbuje użyć mojej bazy danych. – chobo2

+0

@ chobo2, zaktualizowałem odpowiedź. nie zapomnij upvote :) – zvolkov

+0

MembershipProvider.GetUser() jest metodą abstrakcyjną; MembershipUser.PasswordQuestion jest własnością wirtualną –