【问题标题】:RhinoMocks: Correct way to mock property getterRhinoMocks:模拟属性获取器的正确方法
【发布时间】:2008-09-16 23:37:01
【问题描述】:

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

我有一个用户对象,我们称它为 User,它有一个名为 IsAdministrator 的属性。 IsAdministrator 的值通过另一个检查用户安全权限的类进行评估,并根据这些权限返回真或假。我试图模拟这个 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 属性中的依赖关系,我遇到了异常。

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

【问题讨论】:

    标签: tdd rhino-mocks


    【解决方案1】:

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

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

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

    就您的问题而言,您可以通过多种方式处理此问题。您可以将 IsAdministrator 作为用户类上的虚拟属性实现为 aaronjensen,如下所述:

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

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

    实现此目的的另一种方法是使用接口。如果它确实是您想要模拟的 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
    }
    

    如果您愿意,可以使用dependency injection and IOC 来获得更高级的体验,但基本原理是一样的。通常,您希望您的类依赖于接口而不是具体的实现。

    我希望这会有所帮助。我在一个大型项目中使用 RhinoMocks 已经有很长时间了,所以请随时向我询问有关 TDD 和 mocking 的问题。

    【讨论】:

    • 请注意,在对 IUser 存根执行任何操作之前,最后一个示例需要 _mocks.ReplayAll()
    【解决方案2】:

    确保 IsAdministrator 是虚拟的。

    另外,请务必调用 _mocks.ReplayAll()

    【讨论】:

      【解决方案3】:

      _mocks.ReplayAll() 什么都不做。只是因为您使用了不计数的 SetupResult.For()。使用 Expect.Call() 确保您的代码正确无误。

      【讨论】:

        猜你喜欢
        • 2019-09-06
        • 2013-03-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-04-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多