C# 模拟方法结果

C# 模拟方法结果,c#,mocking,rhino-mocks,C#,Mocking,Rhino Mocks,我试图找到一种方法来伪造从另一个方法中调用的方法的结果 我有一个“LoadData”方法,它调用一个单独的助手来获取一些数据,然后它将对其进行转换(我对测试转换的结果感兴趣) 我有这样的代码: public class MyClass(){ public void LoadData(){ SomeProperty = Helper.GetSomeData(); } public object SomeProperty {get;set;} } public class MyCl

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

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

我有这样的代码:

public class MyClass(){
  public void LoadData(){
    SomeProperty = Helper.GetSomeData();
 }
 public object SomeProperty {get;set;}
}
public class MyClass(){
  public void LoadData(IHelper helper){
    SomeProperty = helper.GetSomeData();
 }
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;}
}
我想从Helper.GetSomeData()方法得到一个已知的结果。我可以使用模拟框架(我在Rhino模拟方面的经验相当有限,但对任何事情都持开放态度)来强制实现预期的结果吗?如果是,怎么做


*编辑-是的,正如预期的那样,我无法实现我想要的破解,我必须找到一种更好的方法来设置数据。

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

Rhino Mock、Typemock和Moq都是很好的选择


当我第一次开始使用Rhino Mock时,使用Rhino Mock对我帮助很大。

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


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

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

您必须进行一些重构,才能使用伪GetSomeData()方法注入模拟对象

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

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


注意不要简单地创建一个到Helper类的接口,并通过方法注入它。这可能会暴露实现细节。为什么客户端应该提供一个实用工具的实现来调用一个简单的操作?这将增加MyClass客户端的复杂性。

我将尝试以下方法:

public class MyClass(){
  public void LoadData(){
    SomeProperty = Helper.GetSomeData();
 }
 public object SomeProperty {get;set;}
}
public class MyClass(){
  public void LoadData(IHelper helper){
    SomeProperty = helper.GetSomeData();
 }
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;}
}

通过这种方式,您可以使用例如MOQ来模拟helper类。

我建议将您拥有的转换为如下内容:

public class MyClass(){
  public void LoadData(){
    SomeProperty = Helper.GetSomeData();
 }
 public object SomeProperty {get;set;}
}
public class MyClass(){
  public void LoadData(IHelper helper){
    SomeProperty = helper.GetSomeData();
 }
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;}
}
现在,您的类支持所谓的依赖项注入。这允许您注入helper类的实现,并确保您的类只需要依赖于接口。当您模拟它时,您只需创建一个使用IHelper接口的模拟,并将其传递给构造函数,您的类将使用它,就好像它是真正的Helper类一样

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

如果您想在某个时候更进一步,您可以从修改后的类中完全删除默认的帮助器实现,并使用IoC(控制反转)容器。如果这对你来说是新的,我建议你首先关注为什么所有这些额外的麻烦都是值得的(这是IMHO)

您的单元测试将类似于以下psuedo代码:

public Amazing_Mocking_Test()
{
    //Mock object setup
    MockObject mockery = new MockObject();
    IHelper myMock = (IHelper)mockery.createMockObject<IHelper>();
    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();
}
public惊奇_Mocking_Test()
{
//模拟对象设置
MockObject mockry=新MockObject();
IHelper myMock=(IHelper)mockry.createMockObject();
mockry.On(myMock.Expect(“GetSomeData”).WithNoArguments().Return(任何内容);
//实际测试
MyClass testClass=新的MyClass(myMock);
testClass.LoadData();
//确保模拟满足了所有的期望。
嘲弄。验证期望();
}

如果您有任何问题,请随时发表评论。(顺便说一句,我不知道这些代码是否都有效,我只是在我的浏览器中键入了它,我主要是在说明这些概念)。

您可能需要研究Typemock Isolator,它可以“伪造”方法调用,而不必强制您重构代码。 我是该公司的一名开发人员,但如果您希望选择不更改设计(或被迫不更改其可测试性),则该解决方案是可行的 请访问www.Typemock.com

罗伊
blog:ISerializable.com

AFAIK,如果Helper只是一个普通类,您不能模拟它的方法。请看一看:关于您的警告。。。这实际上叫做控制反转。如果你做得对,这不是一件坏事。:)是的,我知道这个词。是的,如果做对了,非常好。这里的情况并非如此。