【问题标题】:How to mock data access in private methods如何在私有方法中模拟数据访问
【发布时间】:2013-06-11 18:41:02
【问题描述】:

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

   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....
     }
    }

这只是我需要更新的真实代码的一个示例。 当前的单元测试正在对数据库服务进行真正的调用。 我想编写一个单元测试来检查公共 Register() 中的行为,而无需真正调用数据库服务。

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

谢谢你

原产地

【问题讨论】:

  • 您应该使用依赖注入将dataComponentService 对象提供给CustomerService 类。我推荐构造函数注入。在应用程序运行时dataComponentService 被设置为真实的数据库访问实例,但在测试场景中您可以使用模拟对象。网上有很多关于 DI with unit test 的文章,例如 Mark Seemann 的博客:link

标签: c# .net unit-testing mocking rhino-mocks


【解决方案1】:

您需要进行一些依赖注入才能将您的模拟放入您的被测类(有关 DI 的更多信息,请查看 Martin Fowler 的 this article)。首先,您的“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...

... 并将其传递给您的被测类...

var objUt = new CustomerService(dataComponentServiceMock);
objUt.Register();
// check method calls to the mock here...

【讨论】:

  • 当你写一个测试你测试公共方法。在这种情况下,我以私有方法调用其他服务。
  • 感谢您的所有回答。当您编写测试时,您会测试公共方法。在这种情况下,我以私有方法调用其他服务。问题是如何存根对其他服务的响应,以便代码在私有方法中可以继续运行而无需制动?为了测试一个期望在私有方法末尾的行为。
  • 你说的服务是_dataComponentService服务吗?如果是这样,您可以将行为添加到模拟中。如果您想测试私有方法内部发生的事情,除非它们执行一些您可以测试的操作,否则我不确定您如何做。或者,您可以将方法设为内部并将它们公开给您的测试库,如下所述:msdn.microsoft.com/en-us/library/…
  • 我想如果我只写一个测试来处理私有方法中的所有代码,我会更容易。是否可以在私有方法中存根操作?让我们说一下 dataComponentServiceMock.Stub(x=>x.GetInfo).IgnoreAarguments().Return(SomeObject) 谢谢
  • 通过查看您的代码,您在私有方法中进行的唯一方法调用是 _dataComponentService.CheckIfUserExist(userName),您可以使用我的回答中的技术来模拟它。我希望这会有所帮助。
【解决方案2】:

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

最重要的是。即使你有一个私有方法。您可以放松它以保护它并使其虚拟化。如果它是虚拟的,您可以制作一个特殊的类的测试版本,在其中以不同的方式实现受保护的成员。

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-07-14
    • 1970-01-01
    相关资源
    最近更新 更多