gpt4 book ai didi

c# - 使用 Rhino Mocks 模拟阻塞调用

转载 作者:太空宇宙 更新时间:2023-11-03 22:18:17 25 4
gpt4 key购买 nike

我目前正在使用 TDD 构建一个类。该类负责等待特定窗口变为事件状态,然后触发某些方法。

我正在使用 AutoIt COM 库(有关 AutoIt 的更多信息请查看 here )因为我想要的行为实际上是 AutoIt 中的一个方法。

代码大致如下:

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 库实现了一个我可以模拟的接口(interface)(使用 NUnit 和 Rhino Mocks):

[TestFixture]
public class When_running_the_monitor
{
WindowMonitor subject;
IAutoItX3 mockAutoItLibrary;
AutoResetEvent continueWinWaitActive;
AutoResetEvent winWaitActiveIsCalled;


[SetUp]
public void Setup()
{
// Arrange
mockAutoItLibrary = MockRepository.GenerateStub<IAutoItX3>();
mockAutoItLib.Stub(m => m.WinWaitActive("", "", 0))
.IgnoreArguments()
.Do((Func<string, string, int, int>) ((a, b, c) =>
{
winWaitActiveIsCalled.Set();
continueWinWaitActive.WaitOne();
return 1;
}));

subject = new Subject(mockAutoItLibrary)

// Act
new Thread(new ThreadStart(subject.Run)).Start();
winWaitActiveIsCalled.WaitOne();
}

// Assert

[Test]
[Timeout(1000)]
public void should_call_winWaitActive()
{
mockAutoItLib.AssertWasCalled(m => m.WinWaitActive("Bestand selecteren", "", 0));
}

[Test]
[Timeout(1000)]
public void ensure_that_nothing_is_done_while_window_is_not_active_yet()
{
// When you do an "AssertWasCalled" for the actions when the window becomes active, put an equivalent "AssertWasNotCalled" here.

}

问题是,第一个测试总是超时。我已经发现,当调用 stub “WinWaitActive”时,它会阻塞(如预期的那样,在单独的线程上),并且当之后调用“AssertWasCalled”时,执行永远不会返回。

我不知道如何继续,我找不到任何模拟阻塞调用的例子。

总而言之:

有没有办法在不使测试超时的情况下模拟阻塞调用?

(附:我对更改设计不太感兴趣(即“不要使用阻塞调用”),因为在这里可以这样做,但我确信在某些情况下更难做到更改设计,我对更通用的解决方案感兴趣。但如果模拟阻塞调用根本不可能,那么我们更欢迎这样的建议!)

最佳答案

不确定我是否理解问题。

您的代码只是在模拟 (WinWaitActive) 上调用一个方法。当然,它不能在调用返回之前继续。这是编程语言的本质,无需测试。

因此,如果您测试 WinWaitActive 被调用,您的测试就完成了。您可以测试 WinWaitActive 是否在其他任何事情之前被调用,但这需要有序的期望,这需要旧式 rhino 模拟语法并且通常不值得这样做。

   mockAutoItLibrary = MockRepository.GenerateStub<IAutoItX3>();

subject = new Subject(mockAutoItLibrary)
subject.Run()

mockAutoItLib.AssertWasCalled(m => m.WinWaitActive("Open File", "", 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));

关于c# - 使用 Rhino Mocks 模拟阻塞调用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4216242/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com