C# 我如何重构出一个静态方法,以便测试我的方法?
我知道我不能使用Moq来模拟我的测试方法中的静态方法调用,那么我需要做什么来重构该方法以便测试它呢?我还有一个调用基类方法的方法,我需要重构它吗?如果需要,如何重构?我不想使用MS.Fakes或TypeMock创建一个垫片,我宁愿重构并编写可靠的代码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 =
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);
//断言。相等(“某物”、“某物”);
}
综上所述,您可以测试三个基本条件:
- 从ResolveDate方法的角度来看,当它到达这个分支时,您仍然关心它的值是什么
- 能够证明R1:R5调用静态帮助程序会很好,但正如注释中提到的,唯一干净地做到这一点的方法是用接口包装DateHelper,并将其传递给此类的构造函数。这可能不值得付出努力
- 如果您决定不这样做,我建议您还是给出一个属于该分支的测试,然后还编写另一组测试,直接针对
函数,命中所有边缘情况。这将有助于隔离哪些代码是故障的罪魁祸首DateHelper.PreviousOrCurrentQuarterEnd()
- 再一次,你将很难证明它叫做你的基类
- 但检查结果仍然有效
DateHelper。
我猜您会说不:-D
- 调用report.ResolveDate时
- 它应该抛出空引用异常。使用
`抛出(()=>report.ResolveDate(null,DateTime.Now))
- 解析边界X(如1/1/0001)的日期时,它应等于y
- 当“.”为。。。;(重复你的边/边情况;考虑使用数据驱动)
- 解析边界X的日期时。。。类似于#2,但可能不同于预期结果
- 当计算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
//...
}