所以我有这样的代码:
123456public class MyClass
public void LoadData
SomeProp"/>

关于c#:模拟方法结果

关于c#:模拟方法结果

Mocking method results

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

我有一个" LoadData"方法,该方法调用一个单独的帮助程序以获取一些数据,然后将其转换(我有兴趣测试转换后的结果)。

所以我有这样的代码:

1
2
3
4
5
6
public class MyClass(){
  public void LoadData(){
    SomeProperty = Helper.GetSomeData();
 }
 public object SomeProperty {get;set;}
}

我想从Helper.GetSomeData()方法获得已知结果。我可以使用模拟框架(我对Rhino Mocks的经验有限,但可以接受任何东西)来强制达到预期的结果吗?如果是这样,如何?

* Edit-是的,正如我所料,我无法实现我想要的hack,我必须找到一种更好的方式来设置数据。


您在那里遇到问题。我不知道这是否是代码的简化方案,但是如果以这种方式使用Helper类,则您的代码不可测试。首先,直接使用Helper类,因此您不能用模拟代替它。其次,您要调用静态方法。我不了解C#,但是在Java中,您无法覆盖静态方法。

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

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

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

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


我建议将您拥有的东西转换为如下形式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
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;}
}

现在您的课程支持所谓的依赖注入。这允许您注入帮助程序类的实现,并确保您的类只需要依赖于接口。当您进行模拟时,您只需创建一个使用IHelper接口的模拟并将其传递给构造函数,您的类就将使用它,就好像它是真正的Helper类。

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

如果您想进一步进行此操作,则可以从修订的类中完全删除默认的Helper实现,并使用IoC(控制反转)容器。如果这对您来说是新手,我建议您首先关注为什么所有这些麻烦都值得一去的基本原理(恕我直言)。

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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();
}

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


您可能想研究Typemock隔离器,它可以"伪造"方法调用,而不会强迫您重构代码。
我是该公司的一名开发人员,但是如果您不想选择更改设计(或者为了测试而被迫不更改它),该解决方案是可行的
在www.Typemock.com

罗伊
博客:ISerializable.com


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

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


我会尝试这样的事情:

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

这样,您可以使用例如最小起订量来模拟助手类。


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

Rhino Mocks,Typemock和Moq都是不错的选择。

Steven Walther最初使用Rhino Mocks的文章对我有很大帮助。


推荐阅读

    linux调用函数的命令?

    linux调用函数的命令?,系统,代码,策略,上调,时间,设计,通信,网络,设备,项目,

    linux转换字符集命令?

    linux转换字符集命令?,系统,名称,时间,位置,服务,文件,字符集,命令,格式,以

    linux外部命令调用?

    linux外部命令调用?,系统,软件,标准,命令,盘中,管理,外部,进程,程序,内存,lin

    linux怎么调用命令行?

    linux怎么调用命令行?,系统,地址,工具,工作,首页,终端,命令,密码,信息,情况,l

    浏览器调用linux命令?

    浏览器调用linux命令?,系统,信息,人工智能,软件,数据,首次,地址,代码,咨询,

    py调用linux的命令?

    py调用linux的命令?,系统,代码,状态,环境,标准,工具,命令,文件,脚本,终端,lin

    浏览器调用linux命令?

    浏览器调用linux命令?,系统,信息,人工智能,软件,数据,首次,地址,代码,咨询,

    py调用linux的命令?

    py调用linux的命令?,系统,代码,状态,环境,标准,工具,命令,文件,脚本,终端,lin

    linux模拟请求命令?

    linux模拟请求命令?,地址,工作,系统,工具,信息,标准,命令,目录,发行,数据,lin

    linux系统命令调用?

    linux系统命令调用?,系统,单位,工具,工作,管理,地址,权威,密码,电脑,信息,怎

    linux调用上一条命令?

    linux调用上一条命令?,系统,命令,一致,数字,名称,网上,电脑,目录,空格,终端,l

    linux命令行调用程序?

    linux命令行调用程序?,工具,环境,代码,初级,工程,系统,网上,服务,管理,发行,l

    linux地址转换命令是?

    linux地址转换命令是?,地址,系统,代码,密码,网络,信息,服务,电脑,设备,报告,

    linux使用命令的方法?

    linux使用命令的方法?,系统,信息,工具,标准,数据,命令,左下角,目录,文件夹,

    脚本调用linux命令?

    脚本调用linux命令?,代码,系统,工作,底部,脚本,位置,环境,行用,官网,标准,typ

    调用函数命令linux?

    调用函数命令linux?,系统,管理,网络,通用,统一,观察,地址,代码,设备,地方,怎

    linux命令时间转换?

    linux命令时间转换?,时间,系统,命令,信息,国家,大陆,概念,终端,时区,时分,Lin

    linux内核总调用命令?

    linux内核总调用命令?,工作,地址,系统,信息,管理,策略,命令,目录,时间,基础,

    linux编程调用命令?

    linux编程调用命令?,系统,标准,管理,工作,基础知识,情况,环境,设备,基础,首

    linux命令窗口调用?

    linux命令窗口调用?,系统,工具,首页,终端,命令,数据,盘中,代码,密码,快捷键,