对于基于租户的存储库,什么是更好的可测试方式

时间:2015-02-25 10:27:48

标签: c# unit-testing design-patterns repository-pattern

我有一个存储库,它接收一个数据层作为参数和一个像这样的tenantID。 (代码简化)

 public class MyRepsitory{

        private readonly IDataAccess _dataAccess;
        private readonly string _tenantID;

        public MyRepsitory(IDataAccess dataAccess, string tenantID)
        {
            _dataAccess = dataAccess;
            _tenantID = tenantID;

        }
}
}

此存储库还有一个私有的方法GetClientsForTenantID,这基本上是我的观点,因为每个方法都依赖于GetClientsForTenantID,这不适合单元测试,因为我不能存根或模拟{{1}在我目前的设计中。 这是我目前GetClientsForTenantID方法的当前签名。 GetClientsForTenantID我希望存储库将其作为内部行为来处理,这就是它为私有的原因。我不希望它作为公共成员,因为它对其他开发人员来说是可变的,我的api不可靠。我可以把它变成虚拟的,这样Mocking Framework就可以代理它,但这也感觉不对。

它需要注入一些仅用于测试的假冒客户端,或其他东西......

这显示了我在代码中遇到的问题。 例如,我无法测试我的GetProducts() - 方法

private IEnumerable<string> GetClientsForTenant(string tenantID)

另一个想法是我注入public IEnumerable<Product> GetProducts(string someParameter){ var clients = GetClientsForTenant(this._tenantId); //do some logic that needs to be tested } 基本上是一个类,负责根据tenantID解析客户端。但是这也需要传入IDataAccess,并且会执行应该执行存储库的操作。

像这样:

ITenantStore

感觉也不对,因为TenantStore(IDataAccess dataAccess, string tenantID) MyRepository(IDataAccess dataAccess, ITenantStore tenantStore) 到处都是......

你建议怎样解决这个问题?任何提示提示?

编辑:

感谢您的评论,IDataAccess不在存储库中的GetClientsForTenant上。

我的测试看起来像这样:

DataAccess

由于var mockMockData = new Mock<IDataAccess>(); mockMockData.Setup(x=> x.ExecuteQuery(It.IsAny<IDictionary<string,object>>(),It.IsAny<string>())) .Returns( new List<Product>() ) .Callback<IDictionary<string,object>>( (parameters,sql)=>{ passedInParameters = parameters; }); _repository = new MyRepository(mockMockData.Object,"fakeUser"); var list = _repository.GetProducts(); // Assert the parameters that get's passed into the ExecuteQuery Method because there happens some logic. 在Repository和private上,因此对模拟GetClientsForTenant没有帮助。它只会使用IDataAccess方法调用具有不同参数的DataAccess。

1 个答案:

答案 0 :(得分:2)

+1关于zaitsman的评论。 您似乎已经有一个很好的接缝,允许单独测试MyRepository。

如果a)IDataAccess是一个接口,并且b)你的GetClientsForTenant方法在内部使用它,你可以提供一个假的IDataAccess,返回预先准备好的假冒客户端,你将能够完全测试MyRepository的逻辑而不暴露任何私有方法。

你的直觉就在这里。一般来说,你不应该暴露私人以便进行单元测试。这就是为什么你应该总是专注于测试公开可见的行为,而不是将测试代码绑定到内部实现,如果你试图伪造GetClientsForTenant方法,你会这样做。这将导致脆弱的测试,每次更改某些实现细节时都会破坏(比如在内部调用GetClientsForTenant以外的方法)。

更新:在上一次编辑中你提到:     &#34;由于GetClientsForTenant在Repository和private上,因此对Mock IDataAccess没有帮助。它只会使用不同的参数调用DataAccess,但是来自MyRepository.GetClientsForTenant方法。&#34;

确切地说,这就是重点。您的测试不应该关心存储库的内部实现。是否调用GetClientsForTenant是无关紧要的。然而,重要的是您的存储库如何与其IDataAccess协作者进行通信。