Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/unit-testing/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 使用Moq重写同一类中的虚拟方法_C#_Unit Testing_Moq - Fatal编程技术网

C# 使用Moq重写同一类中的虚拟方法

C# 使用Moq重写同一类中的虚拟方法,c#,unit-testing,moq,C#,Unit Testing,Moq,我们正在使用Moq来单元测试我们的服务类,但是仍然停留在如何测试一个服务方法调用同一类的另一个服务方法的情况上。我尝试将被调用的方法设置为virtual,但仍然不知道在Moq中该怎么做。例如: public class RenewalService : IRenewalService { //we've already tested this public virtual DateTime? GetNextRenewalDate(Guid clientId) {

我们正在使用Moq来单元测试我们的服务类,但是仍然停留在如何测试一个服务方法调用同一类的另一个服务方法的情况上。我尝试将被调用的方法设置为virtual,但仍然不知道在Moq中该怎么做。例如:

public class RenewalService : IRenewalService
{
    //we've already tested this
    public virtual DateTime? GetNextRenewalDate(Guid clientId)
    {
        DateTime? nextRenewalDate = null;
        //...<snip> 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;
    }
}
公共类续订服务:IRenewalService
{
//我们已经测试过了
公共虚拟日期时间?GetNextRenewalDate(Guid clientId)
{
DateTime?nextRenewalDate=null;
//…一吨已经测试过的东西。。。
返回nextRenewalDate;
}
//但是你想在不需要模仿的情况下测试它吗
//GetNextRenewalDate方法中调用的方法
公共图书馆IsLastRenewalOfYear(续展)
{
DateTime?nextRenewalDate=GetNextRenewalDate(renewal.Client.Id);
if(nextRenewalDate==null)
抛出新的异常。DataIntegrityException(“没有计划的续订日期,无法确定是否为去年的最后一次续订”);
如果(nextRenewalDate.Value.Year!=续订.续订日期.年份)
返回true;
返回false;
}
}
在上面的示例中,我们的GetNextRenewalDate方法相当复杂,我们已经对其进行了单元测试。但是,我们希望测试更简单的IsLastRenewalOfYear,而不需要模拟GetNextRenewalDate所需的一切。基本上,我们只是想模拟GetNextRenewalDate


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

编辑:我现在同意这不是Andrew案例的正确答案。我想把这个答案留在这里供评论线程使用。请不要再投反对票了:)

编辑前:

通常,模拟对象框架的设计不是为了简化单个类的场景,而是为了隔离代码,以便您可以测试单个类

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

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


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

在这种情况下,您可能会使用部分模拟,尽管您的所有方法都需要是虚拟的:

    var mock = new Moq.Mock<RenewalService>();
    mock.Setup(m => m.GetNextRenewalDate(It.IsAny<Guid>())).Returns(null);
    mock.CallBase = true;
    var results = mock.Object.IsLastRenewalOfYear(...);
var mock=new Moq.mock();
mock.Setup(m=>m.GetNextRenewalDate(It.IsAny())。返回(null);
mock.CallBase=true;
var results=mock.Object.IsLastRenewalOfYear(…);
var mock=new Moq.mock{CallBase=true};
mock.Setup(m=>m.GetNextRenewalDate(It.IsAny())。返回(null);
var results=mock.Object.IsLastRenewalOfYear(…);

我不确定打破我们的设计是否会让它更易于维护。。。如果我们从5000个类(大约是我们目前拥有的)到10000个类,那么导航就很难了。仅仅为了使设计在特定的工具集中更易于测试而分解设计似乎是个坏主意。沿着这条路走下去,在一个类中很少有方法调用其他公共方法。好的设计怎么样?@Andrew,Jess:我不知道他的应用程序或他的要求,所以请随意接受或离开我的建议。是的,仅仅为了拥有一个方法类而打破它是愚蠢的,但我的其余建议仍然适用。很多时候,当我看到一个“经理”或“服务”类时,抽象不在正确的位置。如果要进行这样的重构,来自其他类的方法可能会在这里结束,或者这些方法可能会在其他类中结束,使这个类完全消失。@Andrew,Jess:至于回答这个问题,我想我应该对此发表评论:)我想我假设通过
创建一个覆盖GetNextRenewalDate的新类,他的意思是放弃这个类的Moq,编写mock/test使他自己加倍。我现在明白了,这可能不是他的意思。我拿走了我的反对票——你的编辑很有道理。我同意有些时候需要重构,但如果类内依赖是标准之一,那么我们所有人都会有一个疯狂的(难以管理的)类激增。。。我甚至不需要把所有的东西都虚拟化(我只是保持上面一样)。@Andrew。上述方法之所以有效,是因为
Mock.CallBase==true
意味着设置不匹配的调用将调用底层实现。因此,
IsLastRenewalOfYear
将调用该实现,因为它不是虚拟的,但是
GetNextRenewalDate
将返回
null
,因为设置将始终匹配。即使IsLastRenewalOfYear
是虚拟的,下面的代码也可以使用。我们在其他几个地方也使用了它,效果非常好。谢谢如果
mock.Object
需要一个构造函数,那么情况会怎样?执行方法时出现错误:无法实例化类:(ClassNameGoeSher)的代理。找不到无参数构造函数。参数名称:constructorArguments@MattyBear模仿(“废话”)
var mock = new Moq.Mock<RenewalService> { CallBase = true };
mock.Setup(m => m.GetNextRenewalDate(It.IsAny<Guid>())).Returns(null);
var results = mock.Object.IsLastRenewalOfYear(...);