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# 我如何重构出一个静态方法,以便测试我的方法?_C#_Unit Testing_Moq_Moq 3 - Fatal编程技术网

C# 我如何重构出一个静态方法,以便测试我的方法?

C# 我如何重构出一个静态方法,以便测试我的方法?,c#,unit-testing,moq,moq-3,C#,Unit Testing,Moq,Moq 3,我知道我不能使用Moq来模拟我的测试方法中的静态方法调用,那么我需要做什么来重构该方法以便测试它呢?我还有一个调用基类方法的方法,我需要重构它吗?如果需要,如何重构?我不想使用MS.Fakes或TypeMock创建一个垫片,我宁愿重构并编写可靠的代码 public override DateTime ResolveDate(ISeries comparisonSeries, DateTime targetDate) { if (comparisonSeries =

我知道我不能使用Moq来模拟我的测试方法中的静态方法调用,那么我需要做什么来重构该方法以便测试它呢?我还有一个调用基类方法的方法,我需要重构它吗?如果需要,如何重构?我不想使用MS.Fakes或TypeMock创建一个垫片,我宁愿重构并编写可靠的代码

    public override DateTime ResolveDate(ISeries comparisonSeries, DateTime targetDate)
    {
        if (comparisonSeries == null)
        {
            throw new ArgumentNullException("comparisonSeries");
        }

        switch (comparisonSeries.Key)
        {
            case SeriesKey.R1:
            case SeriesKey.R2:
            case SeriesKey.R3:
            case SeriesKey.R4:
            case SeriesKey.R5:
                return DateHelper.PreviousOrCurrentQuarterEnd(targetDate);
        }

        return base.ResolveDate(comparisonSeries, targetDate);
    }

    [TestMethod]
    public void SomeTestMethod()
    {
        var mockIAppCache = new Mock<IAppCache>();
        var mockISeries = new Mock<ISeries>();

        ReportFR2 report = new ReportFR2(SeriesKey.FR2, mockIAppCache);
        DateTime resolvedDate = report.ResolveDate(mockISeries, DateTime.Now);

        //Assert.AreEqual("something", "something");

    }
public override DateTime ResolveDate(ISeries比较系列,DateTime targetDate)
{
if(comparisonSeries==null)
{
抛出新ArgumentNullException(“比较序列”);
}
开关(comparisonSeries.Key)
{
案例系列key.R1:
案例系列key.R2:
案例系列key.R3:
案例系列key.R4:
案例系列key.R5:
返回日期helper.PreviousOrCurrentQuarterEnd(targetDate);
}
返回base.ResolveDate(比较系列,targetDate);
}
[测试方法]
public void SomeTestMethod()
{
var mockIAppCache=new Mock();
var mockISeries=new Mock();
ReportFR2 report=新的ReportFR2(SeriesKey.FR2,mockIAppCache);
DateTime resolvedDate=report.ResolveDate(mockISeries,DateTime.Now);
//断言。相等(“某物”、“某物”);
}

综上所述,您可以测试三个基本条件:

  • 当比较序列为空时

  • 当比较系列键为R1:R5时

  • 当比较序列键不为null且除R1:R5以外的任何值时

  • 在条件1中,您可以很容易地通过测试来覆盖这一点

    在条件2中,当它是R1:R5时,它就会出现在您的静态方法中

    • 从ResolveDate方法的角度来看,当它到达这个分支时,您仍然关心它的值是什么
    • 能够证明R1:R5调用静态帮助程序会很好,但正如注释中提到的,唯一干净地做到这一点的方法是用接口包装DateHelper,并将其传递给此类的构造函数。这可能不值得付出努力
    • 如果您决定不这样做,我建议您还是给出一个属于该分支的测试,然后还编写另一组测试,直接针对
      DateHelper.PreviousOrCurrentQuarterEnd()
      函数,命中所有边缘情况。这将有助于隔离哪些代码是故障的罪魁祸首
    条件3和条件2也是如此。尽管它在基类中,但它仍然是一个有效的逻辑分支

    • 再一次,你将很难证明它叫做你的基类

    • 但检查结果仍然有效

    因此,我认为您可以编写四组测试开始,然后在通过这些测试之后,您可以决定是否要重构实用程序类
    DateHelper。
    我猜您会说不:-D

  • 给定一个ReportRF2类和一个空比较序列

    • 调用report.ResolveDate时

    • 它应该抛出空引用异常。使用
      `抛出(()=>report.ResolveDate(null,DateTime.Now))

  • 给定一个ReportRF2类和R1:R5集合中的一个系列键

    • 解析边界X(如1/1/0001)的日期时,它应等于y

    • 当“.”为。。。;(重复你的边/边情况;考虑使用数据驱动)

  • 给定ReportRF2类和一个不在R1:R5和NOTNULL集合中的序列键

    • 解析边界X的日期时。。。类似于#2,但可能不同于预期结果
  • 给定静态实用程序类DateHelper

    • 当计算PreviousOrCurrentQuarterEnd()且日期为X时,它应等于y
    • 类似于上文第2条中的边缘情况
  • 这将为您提供预期结果的覆盖范围,并告诉您失败是由
    ResolveDate
    方法或
    DateHelper.PreviousOrCurrentQuarterEnd()
    方法造成的。它可能不会像纯粹主义者所希望的那样孤立,但只要你涵盖了你的边缘案例和快乐路径,它就证明你的应用程序按计划运行(只要这些测试通过)


    它真正不允许您做的是断言采取了特定的行为,而不是当比较序列为空时,因此由您决定是否需要验证。但是,你仍然应该有证据证明,当某些值或范围进入时,你会得到可预测的输出,这会增加一些价值。

    为了补充@Damon的好答案,可以很容易地用一个接口包装
    DateHelper

    public interface IDateHelper
    {
        DateTime PreviousOrCurrentQuarterEnd(DateTime targetDate);
    }
    

    如前所述,您将需要一个实现此接口的实例类,但仅适用于您的生产代码,因为单元测试将只使用
    mock,或者我想在测试中的方法中调用静态方法吗?我认为答案是否定的,因为单元测试只测试被测试方法中的逻辑,其他什么都不测试,除非它是私有方法。如果我错了,有人纠正我!使用接口包装DateHelper,并将IDateHelper作为方法参数或构造函数参数插入包含类中,就像使用IAppCache一样?有什么更好的方法?1) 用接口包装DateHelper并将其传入,或者2)在类中的“受保护的内部虚拟”方法中隔离静态方法,然后我可以模拟该方法。具体取决于实现。如果DateHelper有一些您希望在测试场景中使用的方法,只需设置您直接调用的方法中现在的内容,虚拟方法可能是一个不错的选择。不过,我会在接口方面出错。如果我在接口方面“出错”,我将不得不将我的类从静态类重构为instance类
    
    public class InstanceDateHelper : IDateHelper
    {
        public DateTime PreviousOrCurrentQuarterEnd(DateTime targetDate)
        {
            return DateTimeHelper.PreviousOrCurrentQuarterEnd(targetDate);
        }
    }
    
    public bool StartProcessAndWaitForExit(ProcessStartInfo info)
    {
        var process = Process.Start(info); // test-hindering static method call
        //...
    }
    
    public bool StartProcessAndWaitForExit(IProcessWrapper process, ProcessStartInfo info)
    {
        var process = process.Start(info); // injected wrapper interface makes method testable
        //...
    }