RhinoMocks:模拟属性获取器的正确方法
我是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可以"伪造"对属性获取器的调用,然后将true返回给我。这不正确吗?当前,由于IsAdministrator属性中的依赖关系,我遇到了异常。
有人可以在这里解释我如何实现我的目标吗?
解决方案
回答
确保IsAdministrator是虚拟的。
另外,请确保我们调用_mocks.ReplayAll()
回答
在我跳到此之前,请快速注意一下。通常,我们要避免使用"严格"模拟,因为它会使测试变脆。如果发生任何未明确告知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 }
如果需要,可以通过使用依赖项注入和IOC来获得更高的要求,但是基本原理是完全相同的。通常,无论如何,我们都希望类依赖于接口而不是具体的实现。
我希望这有帮助。我已经在一个大型项目上使用RhinoMocks很长时间了,所以请随时向我询问有关TDD和模拟的问题。
回答
_mocks.ReplayAll()不会执行任何操作。只是因为我们使用的是SetupResult.For()而不算在内。使用Expect.Call()确保代码正确无误。