Нужна помощь в написании модульного теста для метода, который требует HttpContext.Current.User - PullRequest
3 голосов
/ 21 февраля 2012

Я пытаюсь написать некоторые модульные тесты для моего проекта MVC3 (первые тесты для этого проекта), и я нахожусь в тупике. По сути, у меня есть класс MemberQueries , который используется моим MemberController для обработки всей логики.

Я хочу начать писать тесты для этого класса и начать с простого примера. У меня есть метод в этом классе, который называется IsEditModeAvailable , который определяет, является ли пользователь членом роли «Администратор сайта» или что он может редактировать свои собственные данные, но никто не использует их. Я определяю последнее требование, сравнивая переданное значение Id со свойством HttpContext User.

Проблема, с которой я сталкиваюсь, заключается в том, что я не знаю, как смоделировать или ввести правильные параметры в мои модульные тесты при создании объекта MemberQueries. Я использую NUnit, Moq и Ninject , но я просто не уверен, как написать код. Если я просто не структурирую это должным образом, пожалуйста, дайте мне знать, так как я являюсь полным новичком для модульного тестирования.

Вот пример кода из моего класса MemberQueries:

public class MemberQueries : IMemberQueries
{
  private readonly IRepository<Member> _memberRepository;
  private readonly IMemberServices _memberServices;
  private readonly IPrincipal _currentUser;

  public MemberQueries(IUnitOfWork unitOfWork, IMemberServices memberServices, IPrincipal currentUser)
  {
    _memberRepository = unitOfWork.RepositoryFor<Member>();
    _memberServices = memberServices;
    _currentUser = currentUser;
  }

  public bool IsEditModeAvailable(int memberIdToEdit)
  {
    if (_currentUser.IsInRole("Site Administrator")) return true;
    if (MemberIsLoggedInUser(memberIdToEdit)) return true;
    return false;
  }

  public bool MemberIsLoggedInUser(int memberIdToEdit)
  {
    var loggedInUser = _memberServices.FindByEmail(_currentUser.Identity.Name);
    if (loggedInUser != null && loggedInUser.Id == memberIdToEdit) return true;
    return false;
  }

}

Вот пример из моего класса MemberServices (который находится в моем доменном проекте, на который ссылается MemberQueries):

public class MemberServices : IMemberServices
{
  private readonly IRepository<Member> _memberRepository;

  public MemberServices(IUnitOfWork unitOfWork)
  {
    _memberRepository = unitOfWork.RepositoryFor<Member>();
  }

  public Member Find(int id)
  {
    return _memberRepository.FindById(id);
  }

  public Member FindByEmail(string email)
  {
    return _memberRepository.Find(m => m.Email == email).SingleOrDefault();
  }
}

Наконец, вот заглушка модульного теста, которую я пытаюсь написать:

[Test]
public void LoggedInUserCanEditTheirOwnInformation()
{
  var unitOfWork = new UnitOfWork();

  var currentUser = new Mock<IPrincipal>();
  // I need to somehow tell Moq that the logged in user has a HttpContext.User.Name of "jdoe@acme.com"

  var memberServices = new Mock<MemberServices>();
  // I then need to tell Moq that it's FindByEmail("jdoe@acme.com") method should return a member with a UserId of 1

  var memberQueries = new MemberQueries(unitOfWork, memberServices.Object, currentUser.Object);

  // If the logged in user is "jdoe@acme.com" who has an Id of 1, then IsEditModeAvailable(1) should return true
  Assert.IsTrue(memberQueries.IsEditModeAvailable(1));
}

Ответы [ 2 ]

3 голосов
/ 21 февраля 2012

Похоже, вы пытаетесь проверить метод MemberQueries.IsEditModeAvailable.У вас есть 2 случая, чтобы покрыть здесь.Случай Site Administrators и случай, когда есть зарегистрированный пользователь, чей идентификатор совпадает с идентификатором, переданным в качестве аргументаА поскольку класс MemberQueries основан исключительно на интерфейсах, вы можете издеваться над чем угодно:

[TestMethod]
public void EditMode_Must_Be_Available_For_Site_Administrators()
{
    // arrange
    var unitOfWork = new Mock<IUnitOfWork>();
    var currentUser = new Mock<IPrincipal>();
    currentUser.Setup(x => x.IsInRole("Site Administrator")).Returns(true);
    var memberServices = new Mock<IMemberServices>();
    var memberQueries = new MemberQueries(unitOfWork.Object, memberServices.Object, currentUser.Object);

    // act
    var actual = memberQueries.IsEditModeAvailable(1);

    // assert
    Assert.IsTrue(actual);
}

[TestMethod]
public void EditMode_Must_Be_Available_For_Logged_In_Users_If_His_Id_Matches()
{
    // arrange
    var unitOfWork = new Mock<IUnitOfWork>();
    var currentUser = new Mock<IPrincipal>();
    var identity = new Mock<IIdentity>();
    identity.Setup(x => x.Name).Returns("john.doe@gmail.com");
    currentUser.Setup(x => x.Identity).Returns(identity.Object);
    currentUser.Setup(x => x.IsInRole("Site Administrator")).Returns(false);
    var memberServices = new Mock<IMemberServices>();
    var member = new Member
    {
        Id = 1
    };
    memberServices.Setup(x => x.FindByEmail("john.doe@gmail.com")).Returns(member);
    var memberQueries = new MemberQueries(unitOfWork.Object, memberServices.Object, currentUser.Object);

    // act
    var actual = memberQueries.IsEditModeAvailable(1);

    // assert
    Assert.IsTrue(actual);
}

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

[TestMethod]
public void EditMode_Should_Not_Be_Available_For_Logged_In_Users_If_His_Id_Doesnt_Match()
{
    // arrange
    var unitOfWork = new Mock<IUnitOfWork>();
    var currentUser = new Mock<IPrincipal>();
    var identity = new Mock<IIdentity>();
    identity.Setup(x => x.Name).Returns("john.doe@gmail.com");
    currentUser.Setup(x => x.Identity).Returns(identity.Object);
    currentUser.Setup(x => x.IsInRole("Site Administrator")).Returns(false);
    var memberServices = new Mock<IMemberServices>();
    var member = new Member
    {
        Id = 2
    };
    memberServices.Setup(x => x.FindByEmail("john.doe@gmail.com")).Returns(member);
    var memberQueries = new MemberQueries(unitOfWork.Object, memberServices.Object, currentUser.Object);

    // act
    var actual = memberQueries.IsEditModeAvailable(1);

    // assert
    Assert.IsFalse(actual);
}
2 голосов
/ 21 февраля 2012

Хорошей новостью является то, что вы передаете пользователя как IPrincipal в код, который ему нужен, а не ссылаетесь на HttpContext.Current.User. Все, что вам нужно сделать, это настроить фиктивный IPrincipal так, чтобы он возвращал значения, необходимые для этого теста.

var mockIdentity = new Mock<IIdentity>();
mockIdentity.Setup(x => x.Name).Returns("joe@acme.com");

var mockPrincipal = new Mock<IPrincipal>();
mockPrincipal.Setup(x => x.Identity).Returns(mockIdentity.Object);
...