参考:
Step by step mocking with RhinoMock | My Memory
分三种类型:
- Strict Mock:
GenerateStrictMock<T>,
被调用的函数必须需要实现(Expect或Stub) - Dynamic Mock:GenerateMock<T>, 没实现的部分,默认值返回。
- Partial Mock:GeneratePartialMock<T>,除了被替换的函数,其他的都执行原来的类方法。
- Stubs vs Mocks: 感觉两者差不多,Stub用Except(),Mock用Stub(),例如:_mockDAO.Stub().Return()
- .Repeat.Any(), .Repeat.Once(), .Repeat.Times(10)
_mockDAO.Stub(dao => dao.GetRecordFromDatabase(myRecordId))
.Repeat.Any()
.Return(recordFromDatabase);
- IgnoreArguments():
- 设定约束条件,例如如果参数>10,返回什么
_mockDAO.Stub(dao => dao.GetRecordFromDatabase(Arg<int>.Is.GreaterThanOrEqual(0)))
.Return(recordFromDatabase);
- 参数里某个属性的值是xxx时,返回什么
_mockDAO.Stub(x => x.SomeMethod(myObject))
.Constraints(Property.Value("IsSomethingICareAbout", true)
.Return("foo");
- Mock属性
[Test]
public void TestProperty()
{
var mockedInterface = MockRepository.GenerateMock<IHasAProperty>();
mockedInterface.Expect(x => x.StringProperty).Return("fooString");
Assert.That(mockedInterface.StringProperty, Is.EqualTo("fooString"));
}
- 不用return,用Exception
- 注:不能mock private私有或保护成员,但可以mock interal成员
- 注文中里的BLL :a Business Logic Layer (C#) - Microsoft Learn
- CreateMock创建Mock的时候,要求严格,被调用的函数必须需要实现(Expect或Stub)。而DynamicMock就不需要。
-
[Test] public void TestMock() { ISession session = repository.CreateMock<ISession>(); Expect.Call(session.Subscribe(null)).IgnoreArguments().Return(null).Repeat.Any(); repository.ReplayAll(); Mapper mapper = new Mapper(session); }
- Record/Playback (不是很清楚)
by default, in record mode we can simply start creating our expectations,
then when we’re ready to act on those mocked objects we playback mode using repository.ReplayAll().
执行Expect时候,就开始播放了;当执行ReplayAll就开始回放了。
问题是会放以后才Action? => Mapper mapper = new Mapper(session);
- 针对没有参数函数:void DoSomething()函数的Expect
正确:Expect.Call(session.DoSomething).Repeat.Any();
错误: Expect.Call(session.DoSomething()).Repeat.Any();
- 针对属性public string Result { get; set; }的Expect
Expect.Call(session.Result).Return("hello").Repeat.Any();
- 测试一个private函数的方法,该函数是被事件驱动(重要)
Mocking Event Handlers
LastCall: LastCall allows us to set our expectations on the previous method call.
[Test]
public void TestMock()
{
ISession session = repository.CreateMock<ISession>();
session.StatusChanged += null;
LastCall.IgnoreArguments();
IEventRaiser raiser = LastCall.GetEventRaiser();
repository.ReplayAll();
Mapper mapper = new Mapper(session);
Assert.AreEqual("Connected", mapper.Status);
raiser.Raise(null, null);
Assert.AreEqual("Disconnected", mapper.Status);
}
Notice we use LastCall to create an expectation on the += being called on the StatusChanged event. This should run without any errors.
Notice we use the LastCall.GetEventRaiser() to get an IEventRaiser. This will allow us to raise events on the StatusChanged event.
- 多接口支持,What are the *MultiMocks?
public Mapper(ISession session)
{
Status = "Connected";
this.session = session;
IStatusUpdate status = session as IStatusUpdate;
if (status != null)
{
status.StatusChanged += (sender, e) =>
{
Status = "Disconnected";
};
}
}
注意:IStatusUpdate status = session as IStatusUpdate;
支持写法: ISession session = repository.CreateMultiMock<ISession>(typeof(IStatusUpdate));
- 支持class: PartialMock: 重要!!
- Stubs,CCW最常用的方式
不关心是否被调用过,可以使用这个最简单的方式。