C# 用Rhino Mocks模拟阻塞调用
我目前正在使用TDD构建一个类。该类负责等待特定窗口变为活动状态,然后触发某些方法 我正在使用AutoIt COM库(有关AutoIt外观的更多信息),因为我想要的行为实际上是AutoIt中的一个方法 代码大致如下所示:C# 用Rhino Mocks模拟阻塞调用,c#,multithreading,unit-testing,rhino-mocks,blocking,C#,Multithreading,Unit Testing,Rhino Mocks,Blocking,我目前正在使用TDD构建一个类。该类负责等待特定窗口变为活动状态,然后触发某些方法 我正在使用AutoIt COM库(有关AutoIt外观的更多信息),因为我想要的行为实际上是AutoIt中的一个方法 代码大致如下所示: public class WindowMonitor { private readonly IAutoItX3 _autoItLib; public WindowMonitor(IAutoItX3 autoItLib) { _autoI
public class WindowMonitor
{
private readonly IAutoItX3 _autoItLib;
public WindowMonitor(IAutoItX3 autoItLib)
{
_autoItLib = autoItLib;
}
public void Run() // indefinitely
{
while(true)
{
_autoItLib.WinWaitActive("Open File", "", 0);
// Do stuff now that the window named "Open File" is finally active.
}
}
}
正如您所见,AutoIt COM库实现了一个我可以模拟的接口(使用NUnit和Rhino模拟):
[TestFixture]
运行监视器时的公共类
{
视窗监控主体;
IAutoItX3模拟自动图书馆;
自动存储事件持续处于活动状态;
调用AutoResetEvent WinWaitActives;
[设置]
公共作废设置()
{
//安排
mockAutoItLibrary=MockRepository.GenerateSub();
mockAutoItLib.Stub(m=>m.WinWaitActive(“,”,0))
.IgnoreArguments()
.Do((Func)((a,b,c)=>
{
winWaitActiveIsCalled.Set();
continueWinWaitActive.WaitOne();
返回1;
}));
主题=新主题(mockAutoItLibrary)
//表演
新线程(新线程开始(subject.Run)).Start();
winWaitActiveIsCalled.WaitOne();
}
//断言
[测试]
[超时(1000)]
public void应调用
{
调用mockAutoItLib.Assertwas(m=>m.WinWaitActive(“Bestand selecteren”,0));
}
[测试]
[超时(1000)]
public void确保当窗口处于非活动状态时,什么都没有做()
{
//当您为窗口激活时的操作执行“AssertWasCalled”时,请在此处放置等效的“AssertWasNotCalled”。
}
}
问题是,第一次测试总是超时。我已经发现,当调用存根“WinWaitActive”时,它会阻塞(如预期的那样,在单独的线程上),而当在这之后调用“assertwascall”时,执行永远不会返回
我不知道如何继续,也找不到模拟阻塞调用的任何示例
因此,总而言之:
有没有办法模拟阻塞调用而不使测试超时
(注意,我对更改设计不太感兴趣(即“不要使用阻塞调用”)因为在这里可以做到这一点,但我确信在某些情况下,改变设计要困难得多,而且我对更通用的解决方案感兴趣。但是如果根本不可能模拟阻塞调用,那么像这样的建议更受欢迎!)不确定我是否理解这个问题 您的代码只是在mock(
WinWaitActive
)上调用一个方法。当然,在呼叫返回之前,它无法继续。这是编程语言的本质,不需要测试
因此,如果您测试调用了WinWaitActive
,测试就完成了。您可以先测试WinWaitActive
是否被调用,但这需要有序的期望,这需要老式的rhino mocks语法,通常不值得这么做
mockAutoItLibrary = MockRepository.GenerateStub<IAutoItX3>();
subject = new Subject(mockAutoItLibrary)
subject.Run()
mockAutoItLib.AssertWasCalled(m => m.WinWaitActive("Open File", "", 0));
mockAutoItLibrary=MockRepository.generateSub();
主题=新主题(mockAutoItLibrary)
subject.Run()
调用mockAutoItLib.assertwas(m=>m.WinWaitActive(“打开文件”,“0”);
你不做任何其他事情然后调用一个方法。。。所以没有其他的测试了
编辑:退出无限循环
您可以通过从模拟中抛出异常使其退出无限循环。这不是很好,但是它避免了在单元测试中使用所有这些多线程的东西
mockAutoItLibrary = MockRepository.GenerateStub<IAutoItX3>();
// make loop throw an exception on second call
// to exit the infinite loop
mockAutoItLib
.Stub(m => m.WinWaitActive(
Arg<string>.Is.Anything,
Arg<string>.Is.Anything,
Arg<int>.Is.Anything));
.Repeat.Once();
mockAutoItLib
.Stub(m => m.WinWaitActive(
Arg<string>.Is.Anything,
Arg<string>.Is.Anything,
Arg<int>.Is.Anything));
.Throw(new StopInfiniteLoopException());
subject = new Subject(mockAutoItLibrary)
try
{
subject.Run()
}
catch(StopInfiniteLoopException)
{} // expected exception thrown by mock
mockAutoItLib.AssertWasCalled(m => m.WinWaitActive("Open File", "", 0));
mockAutoItLibrary=MockRepository.generateSub();
//使循环在第二次调用时引发异常
//退出无限循环
mockAutoItLib
.Stub(m=>m.WinWaitActive(
Arg.Is.任何东西,
Arg.Is.任何东西,
参数是任何东西);
.重复一次();
mockAutoItLib
.Stub(m=>m.WinWaitActive(
Arg.Is.任何东西,
Arg.Is.任何东西,
参数是任何东西);
.Throw(new stopInfiniteLopeException());
主题=新主题(mockAutoItLibrary)
尝试
{
subject.Run()
}
catch(stopInfiniteLopeException)
{}//预期模拟引发异常
调用mockAutoItLib.assertwas(m=>m.WinWaitActive(“打开文件”,“0”);
不确定我是否理解这个问题
您的代码只是在mock(WinWaitActive
)上调用一个方法。当然,在呼叫返回之前,它无法继续。这是编程语言的本质,不需要测试
因此,如果您测试调用了WinWaitActive
,测试就完成了。您可以先测试WinWaitActive
是否被调用,但这需要有序的期望,这需要老式的rhino mocks语法,通常不值得这么做
mockAutoItLibrary = MockRepository.GenerateStub<IAutoItX3>();
subject = new Subject(mockAutoItLibrary)
subject.Run()
mockAutoItLib.AssertWasCalled(m => m.WinWaitActive("Open File", "", 0));
mockAutoItLibrary=MockRepository.generateSub();
主题=新主题(mockAutoItLibrary)
subject.Run()
调用mockAutoItLib.assertwas(m=>m.WinWaitActive(“打开文件”,“0”);
你不做任何其他事情然后调用一个方法。。。所以没有其他的测试了
编辑:退出无限循环
您可以通过从模拟中抛出异常使其退出无限循环。这不是很好,但是它避免了在单元测试中使用所有这些多线程的东西
mockAutoItLibrary = MockRepository.GenerateStub<IAutoItX3>();
// make loop throw an exception on second call
// to exit the infinite loop
mockAutoItLib
.Stub(m => m.WinWaitActive(
Arg<string>.Is.Anything,
Arg<string>.Is.Anything,
Arg<int>.Is.Anything));
.Repeat.Once();
mockAutoItLib
.Stub(m => m.WinWaitActive(
Arg<string>.Is.Anything,
Arg<string>.Is.Anything,
Arg<int>.Is.Anything));
.Throw(new StopInfiniteLoopException());
subject = new Subject(mockAutoItLibrary)
try
{
subject.Run()
}
catch(StopInfiniteLoopException)
{} // expected exception thrown by mock
mockAutoItLib.AssertWasCalled(m => m.WinWaitActive("Open File", "", 0));
mockAutoItLibrary=MockRepository.generateSub();
//使循环在第二次调用时引发异常
//退出无限循环
mockAutoItLib
.Stub(m=>m.WinWaitActive(
Arg.Is.任何东西,
Arg.Is.任何东西,
参数是任何东西);
.重复一次();
mockAutoItLib
.Stub(m=>m.WinWaitActive(
Arg.Is.任何东西,
Arg.Is.任何东西,
参数是任何东西);
.Throw(new stopInfiniteLopeException());
主题=新主题(mockAutoItLibrary)
尝试
{
subject.Run()
}
catch(stopInfiniteLopeException)
{}//expe