模拟方法的结果

我试图找到一种方法来伪造从另一个方法中调用的方法的结果。

我有一个“LoadData”方法,它调用一个单独的帮助器来获取一些数据,然后它将对其进行转换(我对测试转换后的结果感兴趣)。

所以我有这样的代码:

public class MyClass(){ public void LoadData(){ SomeProperty = Helper.GetSomeData(); } public object SomeProperty {get;set;} } 

我想从Helper.GetSomeData()方法得到一个已知的结果。 我可以使用一个模拟框架(我对Rhino Mocks的经验相当有限,但对任何事情都很开放)来强制实现预期的结果吗? 如果是这样,怎么样?

*编辑 – 是的,如我所料,我无法实现我想要的黑客攻击,我将不得不找到一种更好的方法来设置数据。

据我所知,您应该为Helper对象创建一个接口或一个基本抽象类。 使用Rhino Mocks,您可以返回所需的值。

或者,您可以为LoadData添加一个重载,该重载接受您通常从Helper对象检索的数据作为参数。 这甚至可能更容易。

你有问题。 我不知道这是否是您的代码的简化方案,但如果以这种方式使用Helper类,那么您的代码是不可测试的。 首先,直接使用Helper类,因此不能用mock替换它 。 其次,您正在调用静态方法。 我不知道C#,但在Java中你无法覆盖静态方法

您将不得不进行一些重构,以便能够使用虚拟GetSomeData()方法注入模拟对象。

在这个简化版本的代码很难给你一个直接的答案。 你有一些选择:

  • 为Helper类创建一个接口,并为客户端提供一种将Helper实现注入MyClass类的方法。 但如果Helper真的是一个实用工具类,那就没有多大意义了。
  • 在MyClass中创建一个名为getSomeData的受保护方法,并使其仅调用Helper.LoadSomeData。 然后将对LoadData中的Helper.LoadSomeData的调用替换为getSomeData。 现在,您可以模拟getSomeData方法以返回虚拟值。

谨防简单地创建Helper类的接口并通过方法注入它。 这可以暴露实现细节。 为什么客户端应该提供实用程序类的实现来调用简单的操作? 这将增加MyClass客户端的复杂性。

我建议将你拥有的东西转换成这样的东西:

 public class MyClass() { private IHelper _helper; public MyClass() { //Default constructor normal code would use. this._helper = new Helper(); } public MyClass(IHelper helper) { if(helper == null) { throw new NullException(); //I forget the exact name but you get my drift ;) } this._helper = helper; } public void LoadData() { SomeProperty = this._helper.GetSomeData(); } public object SomeProperty {get;set;} } 

现在你的类支持所谓的dependency injection。 这允许您注入辅助类的实现,并确保您的类只需要依赖于接口。 当你嘲笑这个时,你就知道你只需创建一个使用IHelper接口并将其传递给构造函数的模拟器,你的类将使用它,就像它是真正的Helper类一样。

现在,如果您使用Helper类作为静态类,那么我建议您使用代理/适配器模式并将静态类包装为另一个支持IHelper接口的类(您还需要创建)。

如果您希望在某个时候更进一步,可以从修订的类中完全删除默认的Helper实现,并使用IoC(Inversion of Control)容器。 如果thiis对你来说是新的,我会建议首先关注为什么所有这些额外的麻烦值得的基础(这是恕我直言)。

您的unit testing看起来像这样的伪代码:

 public Amazing_Mocking_Test() { //Mock object setup MockObject mockery = new MockObject(); IHelper myMock = (IHelper)mockery.createMockObject(); mockery.On(myMock).Expect("GetSomeData").WithNoArguments().Return(Anything); //The actual test MyClass testClass = new MyClass(myMock); testClass.LoadData(); //Ensure the mock had all of it's expectations met. mockery.VerifyExpectations(); } 

如果您有任何疑问,请随时发表评论。 (顺便说一句,我不知道如果这段代码都能正常工作,我只是在浏览器中输入它,我主要是说明这些概念)。

您可能希望查看Typemock Isolator,它可以“伪造”方法调用,而不必强制您重构代码。 我是该公司的开发人员,但如果你想选择不改变你的设计(或者不想改变它的可测试性),那么解决方案是可行的,它可以在www.Typemock.com找到。

Roy博客:ISerializable.com

是的,一个模拟框架正是您正在寻找的。 您可以记录/安排您希望返回某些模拟/存根类的方式。

Rhino Mocks,Typemock和Moq都是这样做的好选择。

当我第一次开始玩Rhino Mocks时, Steven Walther关于使用Rhino Mocks 的post对我帮助很大。

我会尝试这样的事情:

 public class MyClass(){ public void LoadData(IHelper helper){ SomeProperty = helper.GetSomeData(); } 

这样您就可以使用MOQ来模拟辅助类。