1

问题的更新版本

你好。

我的公司有一些遗留代码库,我希望在它们迁移到 .NET 3.5 后立即对其进行测试。我选择了 Moq 作为我的 Mocking 框架(我立即爱上了简洁的语法)。

一个常见的场景,我希望在未来看到很多,是我看到一个与其他一些对象交互的对象。

我知道 Michael Feathers 的作品,而且我越来越擅长识别拐点和隔离尺寸合适的组件。提取和覆盖为王。

但是,有一个功能可以让我的生活变得更轻松。

想象一下 Component1 与 Component2 交互。Component2 是一些奇怪的串行线接口,连接到消防中心或类似的东西,具有大量的字节检查、转换和指针操作。我不想理解 component2 和 Component1 使用的遗留接口带来了很多包袱。

我想做的是提取 Component1 使用的 Component2 的接口,然后执行以下操作:

 component1.FireCentral = new Mock<IComponent2> (component2);

我正在创建一个普通的模拟,但我正在将真实 Component2 的一个实例作为构造函数参数传递到 Mock 对象中。看起来我正在根据 Component2 进行测试,但我不打算保留此代码。这是“放置测试对象”仪式的一部分。

现在,我将启动真实系统(连接物理火中心),然后与我的对象进行交互。

然后我希望检查模拟以查看组件 1 如何与组件 2 交互的日志(使用调试器检查模拟上的一些字符串集合)。而且,更好的是,该模拟可以提供一个期望列表(在 C# 中),它将在不依赖于 Component2 的模拟中创建此行为,然后我将在我的测试代码中使用它。

简而言之。使用模拟框架记录交互,以便我可以在我的测试代码中回放它。

旧版问题

你好。

使用遗留代码和许多实用程序类时,我有时会发现自己想知道在许多场景中特定类是如何被其周围环境所作用的。我今天早上处理的一个案例涉及对常规 MemoryStream 进行子类化,以便在达到一定大小时将其内容转储到文件中。

// TODO: Remove
private class MyLimitedMemoryStream : MemoryStream
{
    public override void Write(byte[] buffer, int offset, int count)
    {
        if (GetBuffer().Length > 10000000)
        {
            System.IO.FileStream file = new FileStream("c:\\foobar.html",FileMode.Create);
            var internalbuffer = GetBuffer();
            file.Write(internalbuffer,0,internalbuffer.Length);
        }
        base.Write(buffer, offset, count);
    }        
}

(我在这里使用了一个断点在文件写入后退出程序)。这行得通,我发现哪个 webform(web 部件->web 部件->web 部件)控件呈现不正确。然而,memorystream 有一堆 write 和 writeline。

我可以使用模拟框架快速了解特定实例的操作方式吗?有什么巧妙的技巧吗?我们使用 Rhino Mocks。

我认为这是处理遗留代码的重要资产。特别是如果可以轻松地将场景中记录的操作设置为在单元测试中复制的同一场景的新期望/接受标准。

每一个输入都受到赞赏。感谢您的阅读。

4

4 回答 4

2

欢迎来到了解此要求的“有远见者”小俱乐部:)

不幸的是,我会告诉你,我认为 .NET 尚不存在此功能。我也很确定 Java 也不存在它......因为我已经定期搜索了几年,甚至在按工作付费的网站上为此提供了现金奖励,但没有任何结果(一些俄罗斯开发商提出从头开始实施它,但它超出了我的预算)。

但是,我在 PHP 中创建了一个 Proof Of Concept 来演示这个想法,也许还有其他人有兴趣为其他语言开发这个(.NET 对你来说,Java 对我来说)。

这是 PHP 的概念验证:

http://code.google.com/p/php-mock-recorder/

于 2009-10-28T15:25:35.450 回答
0

是的,这是可能的。如果您使用严格的模拟并运行一个单元测试来执行模拟,测试将失败,并告诉您调用了哪个意外方法。

这是你要找的吗?

于 2009-10-18T05:35:02.337 回答
0

我不认为您可以使用模拟框架来轻松了解特定实例的操作方式。

但是,您可以使用模拟框架来定义应如何对其进行操作,以验证是否以这种方式对其进行操作。在遗留代码中,这通常需要使代码可测试,例如引入接口等。

一种无需对代码进行大量重组即可与遗留代码一起使用的技术是使用日志接缝。您可以在 InfoQ 文章中阅读更多相关信息:使用 Logging Seams 进行遗留代码单元测试

如果您想了解有关如何测试遗留代码的更多提示,我推荐Michael Feathers所著的《有效地使用遗留代码》一书。

希望这可以帮助!

于 2009-07-02T10:18:37.547 回答
0

模拟框架不是为这个问题而设计的。我看不出如何使用 Moq 或 RhinoMocks 进行这项工作。即使是功能强大的 TypeMock 也可能无法满足您的要求。模拟框架不是为此而构建的。

相反,使用面向方面的编程 (AOP) 工具来编织方法调用前后的调用。这将完全符合您的要求:查看特定类型的所有交互。例如,在PostSharp AOP 框架中,您只需指定要在对其他对象进行方法调用之前和之后调用的方法:

public class Component2TracerAttribute : OnMethodBoundaryAspect 
{ 
  public override void OnEntry( MethodExecutionEventArgs eventArgs) 
  { 
     if (eventArgs.Method == somethingOnComponent2) // Pseudo-code
     {
        Trace.TraceInformation("Entering {0}.", eventArgs.Method);  
     }
  } 

  public override void OnExit(MethodExecutionEventArgs eventArgs) 
  { 
      if (eventArgs.Method == somethingOnComponent2) // Pseudo-code
      {
         Trace.TraceInformation("Leaving {0}.", eventArgs.Method);   
      }
  } 
}

这将记录在组件 2 上调用的所有方法。

于 2009-10-19T14:46:09.813 回答