Насмешливый членство пользователя - PullRequest
9 голосов
/ 23 ноября 2010

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

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

public interface IStaticMembershipService {
    MembershipUser GetUser();

    void UpdateUser(MembershipUser user);
}

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

Я использую moq в качестве среды для насмешек.

Ответы [ 4 ]

11 голосов
/ 23 ноября 2010

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

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 является poco-подобным объектом, и вы можете создатьтакой пример:

var userMock = new MembershipUser {ProviderUserKey = guid};
2 голосов
/ 23 ноября 2010

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

public interface IMembershipDetailsService {
    Guid UserKey { get; }
}

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

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

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

1 голос
/ 23 ноября 2010

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

var user = new MembershipUser();
var membershipService = new Mock<IStaticMembershipService>();
membershipService.Setup(p => p.GetUser()).Returns(user);
0 голосов
/ 23 ноября 2010

Не могли бы вы сделать что-то, как показано ниже, если вам тоже нужно макетировать материал 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   
}
...