C# 如何在私有方法中模拟数据访问

C# 如何在私有方法中模拟数据访问,c#,.net,unit-testing,mocking,rhino-mocks,C#,.net,Unit Testing,Mocking,Rhino Mocks,我想问下一个示例中如何使用rhino Mock: Public Class CustomerService { Public void Register() { Action1(); Action2(); } private action1 () { //this is a call to other dll. var isExist = _dataComponen

我想问下一个示例中如何使用rhino Mock:

   Public Class CustomerService 
    {
      Public void Register()
     {
         Action1();
         Action2();
     }

    private action1 ()
     {
       //this is a call to other dll.
       var isExist = _dataComponentService.CheckIfUserExist(userName);
     } 
   private action2()
     {
       //do some more work...
       // Call to dataComponentService. write some data in the database....
     }
    }
这只是我需要更新的真实代码的一个示例。 当前的单元测试正在对数据库服务进行真正的调用。 我想编写一个单元测试来检查public Register()中的行为,而不需要真正调用数据库服务

是否可以模拟对位于私有方法中的其他组件的调用,而无需重新写入hole服务

提前谢谢你


Ori

您需要进行一些依赖注入,以便将您的mock放入测试中的类中(有关DI的更多信息,请查看Martin Fowler)。首先,“dataComponentService”类需要实现一个接口:

public interface IDataComponentService
{
    boolean CheckIfUserExist(String user);
}
然后,您可以通过添加适当的构造函数将实现该接口的类注入CustomerService类:

public class CustomerService 
{
    private IDataComponentService _dataComponentService

    // This constructor allows you to inject your dependency into the class
    public CustomerService(IDataComponentService dataComponentService)
    {
        _dataComponentService = dataComponentService;
    }

    Public void Register()
    {
        Action1();
        Action2();
    }

    private action1 ()
    {
        //this is a call to other dll.
        var isExist = _dataComponentService.CheckIfUserExist(userName);
    } 

    private action2()
    {
       //do some more work...
       // Call to dataComponentService. write some data in the database....
    }
}
现在,在测试代码中,您可以创建IDataComponentService的模拟

var dataComponentServiceMock = MockRepository.GenerateMock<IDataComponentService>(); 
//add mock's behavior here...

您需要进行一些依赖项注入,以便将您的mock放入正在测试的类中(有关DI的更多信息,请查看Martin Fowler)。首先,“dataComponentService”类需要实现一个接口:

public interface IDataComponentService
{
    boolean CheckIfUserExist(String user);
}
然后,您可以通过添加适当的构造函数将实现该接口的类注入CustomerService类:

public class CustomerService 
{
    private IDataComponentService _dataComponentService

    // This constructor allows you to inject your dependency into the class
    public CustomerService(IDataComponentService dataComponentService)
    {
        _dataComponentService = dataComponentService;
    }

    Public void Register()
    {
        Action1();
        Action2();
    }

    private action1 ()
    {
        //this is a call to other dll.
        var isExist = _dataComponentService.CheckIfUserExist(userName);
    } 

    private action2()
    {
       //do some more work...
       // Call to dataComponentService. write some data in the database....
    }
}
现在,在测试代码中,您可以创建IDataComponentService的模拟

var dataComponentServiceMock = MockRepository.GenerateMock<IDataComponentService>(); 
//add mock's behavior here...

你的问题引起了我的一些怀疑。 第一:如果单元测试正在执行数据库访问,那么它就不是单元测试。如果它正在进行数据库访问,那么它更像是一个集成测试。 第二:您应该更多地依赖依赖依赖注入,并开始向接口而不是对象编程。这意味着您将插入必须为_datacomponentservice定义的接口

除此之外。即使你有一个私有的方法。您可以将其放松,使其受到保护并成为虚拟的。如果它是虚拟的,您可以为类创建一个特殊的测试版本,在这个版本中,您可以以不同的方式实现受保护的成员


许多人正在定义许多私有方法,但我发现有时这会阻碍未来的发展,我宁愿让它们受到保护,而不是私有。因为你永远不知道未来会怎样。例如,我使用.NETReflector浏览microsofts的代码,比如combobox,希望使它更灵活。有时我会花很长时间去做这件事,因为有些方法和类甚至在派生类中是不可访问的。

你的问题引起了我的一些怀疑。 第一:如果单元测试正在执行数据库访问,那么它就不是单元测试。如果它正在进行数据库访问,那么它更像是一个集成测试。 第二:您应该更多地依赖依赖依赖注入,并开始向接口而不是对象编程。这意味着您将插入必须为_datacomponentservice定义的接口

除此之外。即使你有一个私有的方法。您可以将其放松,使其受到保护并成为虚拟的。如果它是虚拟的,您可以为类创建一个特殊的测试版本,在这个版本中,您可以以不同的方式实现受保护的成员


许多人正在定义许多私有方法,但我发现有时这会阻碍未来的发展,我宁愿让它们受到保护,而不是私有。因为你永远不知道未来会怎样。例如,我使用.NETReflector浏览microsofts的代码,比如combobox,希望使它更灵活。有时我会花很多时间去做这件事,因为有些方法和类甚至在派生类中是不可访问的。

您应该使用依赖项注入来向
CustomerService
类提供
dataComponentService
对象。我推荐构造函数注入。在应用程序运行时,
dataComponentService
被设置为真实的数据库访问实例,但在测试场景中,您可以使用mock对象。Web上有很多关于使用单元测试的DI的文章,例如Mark Seemann的博客:。您应该使用依赖注入为
CustomerService
类提供
dataComponentService
对象。我推荐构造函数注入。在应用程序运行时,
dataComponentService
被设置为真实的数据库访问实例,但在测试场景中,您可以使用mock对象。Web上有很多关于使用单元测试的DI的文章,例如Mark Seemann的博客:。当您编写测试时,您测试公共方法。在这种情况下,我用私人方式打电话给其他服务。谢谢你的回答。编写测试时,您测试公共方法。在本例中,我使用私有方法调用其他服务。问题是我如何将响应存根到其他服务,以便代码在私有方法中时可以继续而不中断?为了测试一个Expect,需要一个位于私有方法末尾的行为。您所说的服务是_dataComponentService服务吗?如果是这样,您可以将行为添加到模拟中。如果您想测试私有方法中发生的事情,我不确定如何测试,除非它们执行一些您可以测试的操作。或者,您可以将这些方法设置为内部方法,并将它们公开到您的测试库中,如下所述:我想,如果我只编写一个测试,该测试将与私有方法中的所有代码一起进行,那么会更容易。是否可以在私有方法中存根一个操作?比如说dataComponentServiceMock.Stub(x=>x.GetInfo).IgnoreAarguments().Return(SomeObject)感谢您查看代码。您在私有方法中进行的唯一方法调用是_dataComponentService.CheckIfUserExist(userName),您可以使用我的回答中的技术来模拟它。我希望这能有所帮助。当你编写一个测试时,你要测试公共方法。在这种情况下,我使用私有方法调用其他服务。谢谢