Подтвердить что ты не робот

RhinoMocks: правильный способ издеваться над имуществом

Я новичок в RhinoMocks и пытаюсь понять синтаксис в дополнение к тому, что происходит под капотом.

У меня есть пользовательский объект, мы будем называть его User, у которого есть свойство IsAdministrator. Значение для IsAdministrator оценивается через другой класс, который проверяет права доступа пользователя и возвращает либо true, либо false на основе этих разрешений. Я пытаюсь высмеять этот класс пользователя и подделку возвращаемого значения для IsAdministrator, чтобы изолировать некоторые тесты Unit.

Это то, что я делаю до сих пор:

public void CreateSomethingIfUserHasAdminPermissions()
{
    User user = _mocks.StrictMock<User>();
    SetupResult.For(user.IsAdministrator).Return(true);

    // do something with my User object
} 

Теперь, я ожидаю, что Rhino собирается "подделать" звонок на свойство getter и просто вернуть мне правду. Это неверно? В настоящее время я получаю исключение из-за зависимостей в свойстве IsAdministrator.

Может кто-нибудь объяснить, как я могу достичь своей цели здесь?

4b9b3361

Ответ 1

Одна быстрая заметка, прежде чем я в нее вскочу. Как правило, вы хотите избежать использования "Строгого" макета, потому что это делает хрупкий тест. Строгий макет будет генерировать исключение, если что-то случится, что вы явно не сообщите, что Rhino произойдет. Также я думаю, что вы можете неправильно понимать, что делает Rhino, когда вы делаете звонок, чтобы создать макет. Подумайте об этом как о пользовательском объекте, который был либо получен, либо реализует определенный вами System.Type. Если бы вы сделали это сами, это выглядело бы так:

public class FakeUserType: User
{
    //overriding code here
}

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

Что касается вашего вопроса, есть несколько способов справиться с этим. Вы можете реализовать IsAdministrator как виртуальное свойство в своем пользовательском классе как aaronjensen, упомянутое ниже:

public class User
{
    public virtual Boolean IsAdministrator { get; set; }
}

Это одобренный подход, но только если вы планируете наследовать от своего класса User. Кроме того, если вы не подделываете других участников этого класса, они также должны быть виртуальными, что, вероятно, не является желаемым поведением.

Другим способом добиться этого является использование интерфейсов. Если это действительно класс пользователя, который вы хотите выполнить Mock, я бы извлек из него интерфейс. Ваш пример выше будет выглядеть примерно так:

public interface IUser
{
    Boolean IsAdministrator { get; }
}

public class User : IUser
{
    private UserSecurity _userSecurity = new UserSecurity();

    public Boolean IsAdministrator
    {
        get { return _userSecurity.HasAccess("AdminPermissions"); }
    }
}

public void CreateSomethingIfUserHasAdminPermissions()
{
    IUser user = _mocks.StrictMock<IUser>();
    SetupResult.For(user.IsAdministrator).Return(true);

    // do something with my User object
}

Вы можете получить более привлекательный, если хотите, с помощью инъекции зависимостей и IOC, но основной принцип один и тот же по всем направлениям. Как правило, вы хотите, чтобы ваши классы зависели от интерфейсов, а не от конкретных реализаций.

Надеюсь, это поможет. Я давно использую RhinoMocks в крупном проекте, поэтому не стесняйтесь задавать мне вопросы о TDD и насмехаться.

Ответ 2

Убедитесь, что IsAdministrator является виртуальным.

Кроме того, убедитесь, что вы вызываете _mocks.ReplayAll()

Ответ 3

_mocks.ReplayAll() ничего не сделает. Это просто потому, что вы используете SetupResult.For(), который не учитывается. Используйте Expect.Call(), чтобы убедиться, что ваш код делает все правильно.