使用Moq覆盖同一类中的虚方法

我们使用Moq对我们的服务类进行unit testing,但是他们仍然坚持如何测试服务方法调用同一类的另一个服务方法的情况。 我尝试将被调用的方法设置为虚拟,但仍然无法弄清楚在Moq中要做什么。 例如:

public class RenewalService : IRenewalService { //we've already tested this public virtual DateTime? GetNextRenewalDate(Guid clientId) { DateTime? nextRenewalDate = null; //... a ton of already tested stuff... return nextRenewalDate; } //but want to test this without needing to mock all //the methods called in the GetNextRenewalDate method public bool IsLastRenewalOfYear(Renewal renewal) { DateTime? nextRenewalDate = GetNextRenewalDate(renewal.Client.Id); if (nextRenewalDate == null) throw new Exceptions.DataIntegrityException("No scheduled renewal date, cannot determine if last renewal of year"); if (nextRenewalDate.Value.Year != renewal.RenewDate.Year) return true; return false; } } 

在上面的例子中,我们的GetNextRenewalDate方法非常复杂,我们已经对它进行了unit testing。 但是,我们想要测试更简单的IsLastRenewalOfYear,而无需模拟GetNextRenewalDate所需的所有内容。 基本上,我们只想模拟GetNextRenewalDate。

我意识到我可以创建一个覆盖GetNextRenewalDate并测试新类的新类,但有没有办法可以利用Moq使这更简单?

您可以在此场景中使用部分模拟,尽管您的所有方法都需要是虚拟的:

  var mock = new Moq.Mock(); mock.Setup(m => m.GetNextRenewalDate(It.IsAny())).Returns(null); mock.CallBase = true; var results = mock.Object.IsLastRenewalOfYear(...); 

编辑 :我现在同意这不是安德鲁案件的正确答案。 我想在这里为评论主题留下这个答案。 请不要再投票了:)

编辑前:

通常,模拟对象框架不是为简化单个类方案而设计的,它们旨在隔离您的代码,以便您可以测试单个类。

如果您尝试使用模拟对象框架来解决此问题,那么框架将创建一个派生类并重载该方法。 唯一不同的是,您可以在大约3行而不是5行中执行此操作,因为您不必创建派生类定义。

如果您想使用模拟对象来隔离此行为,那么您应该稍微拆分此类。 GetNextRenewalDate逻辑可以位于RenewalService对象之外。

您遇到此问题的事实可能表明,有一个更简单或更细粒度的设计尚待发现。 找到一个不那么具体的类,名称如“manager”或“service”通常暗示你可以将你的设计分解成更小的类,并从中获得更好的可重用性和可维护性。

 var mock = new Moq.Mock { CallBase = true }; mock.Setup(m => m.GetNextRenewalDate(It.IsAny())).Returns(null); var results = mock.Object.IsLastRenewalOfYear(...);