我是 RhinoMocks 的新手,除了了解幕后发生的事情之外,我还试图掌握其语法。

我有一个用户对象,我们将其称为 User,它有一个名为 IsAdministrator 的属性。IsAdministrator 的值通过另一个类进行评估,该类检查用户的安全权限,并根据这些权限返回 true 或 false。我正在尝试模拟这个 User 类,并伪造 IsAdministrator 的返回值以隔离一些单元测试。

这就是我到目前为止正在做的事情:

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

    // do something with my User object
} 

现在,我期望 Rhino 会“伪造”对属性 getter 的调用,然后返回 true 给我。这是不正确的吗?目前,由于 IsAdministrator 属性中的依赖项,我遇到了异常。

有人可以解释我如何在这里实现我的目标吗?

有帮助吗?

解决方案

在我开始讨论这个之前,请先简单说明一下。通常,您希望避免使用“严格”模拟,因为它会导致测试变得脆弱。如果发生您没有明确告诉 Rhino 的任何事情,严格模拟将抛出异常。另外,我认为当您调用创建模拟时,您可能会误解 Rhino 正在做什么。将其视为派生自您定义的 System.Type 或实现您定义的 System.Type 的自定义对象。如果你自己做的话,它看起来像这样:

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

由于 IsAdministrator 可能只是 User 类型的公共属性,因此您无法在继承类型中覆盖它。

就你的问题而言,有多种方法可以解决这个问题。您可以将 IsAdministrator 实现为用户类的虚拟属性,如下所示 亚伦詹森 提及如下:

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

这是一个不错的方法,但前提是您计划从 User 类继承。此外,如果您不想伪造此类中的其他成员,他们也必须是虚拟的,这可能不是所需的行为。

实现此目的的另一种方法是使用接口。如果它确实是您想要 Mock 的 User 类,那么我会从中提取一个接口。你上面的例子看起来像这样:

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 和模拟的问题。

其他提示

确保 IsAdministrator 是虚拟的。

另外,请确保您调用 _mocks.ReplayAll()

_mocks.ReplayAll() 不会执行任何操作。这只是因为您使用了SetupResult.For(),这不算数。使用 Expect.Call() 确保您的代码正确执行所有操作。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top