2010-11-23 3 views
9

В настоящее время я разрабатываю приложение asp.net mvc 2, которое использует аутентификацию по умолчанию SqlMembershipProvider. Я реализовал метод контроллера, который считывает ProviderUserKey текущего пользователя, вызывая Membership.GetUser().ProviderUserKey. Теперь я пытаюсь написать некоторые методы тестирования для этого контроллера.Mocking a MemberhipUser

Чтобы избавиться от зависимостей на статическом классе Membership, я создал тонкую оболочку и сделал мой контроллер зависит от соответствующего интерфейса:

public interface IStaticMembershipService { 
    MembershipUser GetUser(); 

    void UpdateUser(MembershipUser user); 
} 

До сих пор все работает, но для того, чтобы блок -тестируйте контроллер, мне все же нужно высмеять метод GetUser() этого интерфейса и вернуть объект MembershipUser, содержащий свойство ProviderUserKey. Каков самый простой способ издеваться над таким объектом?

Я использую moq как насмешливый фреймворк.

ответ

11

Было бы выглядеть примерно так:

var membershipMock = new Mock<IStaticMembershipService>(); 
var userMock = new Mock<MembershipUser>(); 
userMock.Setup(u => u.ProviderUserKey).Returns(guid); 
membershipMock.Setup(s => s.GetUser()).Returns(userMock.Object); 

Если класс MembershipUser не поддается насмешливый (т.е. если ProviderUserKey не является виртуальным), вы захотите создать свой собственный объект для представления значений, которые вам понадобятся от объекта MembershipUser, и попросите службу вернуть один из них.

Там также небольшая вероятность того, что MembershipUser является росо-подобным объектом, и вы можете создать экземпляр вроде этого:

var userMock = new MembershipUser {ProviderUserKey = guid}; 
+0

Большое спасибо, создавая макет класса MembershipUser отлично. – Simon 2010-11-24 09:05:54

1

Что-то похожее на это:

var user = new MembershipUser(); 
var membershipService = new Mock<IStaticMembershipService>(); 
membershipService.Setup(p => p.GetUser()).Returns(user); 
2

Я думаю, вам нужно отделить особенности реализации от интерфейса потребителя действительно заботится о. Я не уверен, что для вашего контроля нужен ProviderUserKey, если он переводит его в определенный класс и т. Д., Но я бы посмотрел на то, чтобы ваш интерфейс действительно отвечал потребностям контроллера, а не наоборот. Нечто подобное (не зная больше деталей):

public interface IMembershipDetailsService { 
    Guid UserKey { get; } 
} 

После того, как вы сделаете такой уровень абстракции, то насмешливый становится намного легче, потому что вы можете просто сделать:

membershipService.Setup (svc => svc.UserKey).Returns (myGuid); 

Просто еще одна мысль, а не пытаться для возврата целого объекта MembershipUser, который вам нужен для дальнейшего заглушки.

+0

+1 Очень хорошая точка. – StriplingWarrior 2010-11-27 17:59:03

0

Не могли бы вы сделать что-то вроде ниже, если вам нужно также выкрикнуть материал HttpContext .. ниже используется NUnit и Moq.

[SetUp] 
private void Setup() 
{ 
    _mockHttpContext = new Mock<HttpContextBase>(); 
    _mockStaticMembership = new Mock<IStaticMembershipService>();   
    _mockUser = new Mock<MembershipUser>(); 
    _mockPrincipalUser = new Mock<IPrincipal>();   

    _mockHttpContext.Setup(http => http.User).Returns(_mockPrincipalUser.Object); 
    _mockPrincipalUser.Setup(principal => principal.Identity.Name).Returns("myname"); 
    _mockUser.Setup(user => user.ProviderUserKey).Returns(Guid.NewGuid()); 

    _mockStaticMembership.Setup(membership => membership.GetUser(It.IsAny<string>())).Returns(_mockUser.Object); 

} 

[Test] 
public void Some_Test_For_My_Controller() 
{    
    var controller = new MyController(_mockStaticMembership.Object);    
    controller.ControllerContext = new ControllerContext(_mockHttpContext.Object, new RouteData(), controller); 

    //Test your action and verify 
} 
Смежные вопросы