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

时间:2013-06-11 18:41:02

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

我想问一下如何在下一个例子中使用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()中的行为,而不需要对数据库服务进行真正的调用。

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

先谢谢你

大利

2 个答案:

答案 0 :(得分:3)

你需要做一些依赖注入才能让你的模拟进入你的被测试阶段(有关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...

答案 1 :(得分:2)

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

定义的接口

除此之外。即使你有私人方法。您可以放松它,也许可以保护并使其成为虚拟。如果它是虚拟的,您可以使用不同的方式创建类的特殊测试版本。

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