C# 如何测试隐藏测试数据的服务方法
想象一下,我的asp.net mvc控制器方法可能有以下代码:C# 如何测试隐藏测试数据的服务方法,c#,asp.net-mvc,unit-testing,controller,C#,Asp.net Mvc,Unit Testing,Controller,想象一下,我的asp.net mvc控制器方法可能有以下代码: testplanService.AddTestplan(testplan,template,release); 它调用以下实现的服务方法: public TestplanService { public void AddTestplan(Testplan testplan, Template template, Release release) { testplan.CreatedAt =
testplanService.AddTestplan(testplan,template,release);
它调用以下实现的服务方法:
public TestplanService
{
public void AddTestplan(Testplan testplan, Template template, Release release)
{
testplan.CreatedAt = DateTime.Now;
testplan.UserId = WindowsIdentity.GetCurrent().Name;
testplan.Name = release.Name + " " + template.Name + " " + testplan.UserId + " " + testplan.CreatedAt;
_provider.AddTestplan(testplan, template, release);
}
}
当我不知道时,如何测试断言中的CreatedAt、UserId和Name属性
此方法中的值是多少
是的,我知道我可以在testplan对象内传递所有3个值,该对象无论如何都会传递给服务方法,但是mvc中的控制器类不应该有这3行逻辑
那你会怎么做
想象一下,我的asp.net mvc控制器方法可以有这样的功能
代码:
testplanService.AddTestplan(测试计划、模板、发布)代码>
我不想想象那样的事情。正确的方法是控制器使用抽象,而不是实际实现。因此,您在控制器中使用的testplanService
变量将是一个简单的接口或抽象类,而不是依赖于实际的服务实现,它将被注入控制器的构造函数中
现在,在单元测试中,您可以模拟此接口并单独测试控制器
现在让我们考虑服务的实际实现:
public void AddTestplan(Testplan testplan, Template template, Release release)
{
testplan.CreatedAt = DateTime.Now;
testplan.UserId = WindowsIdentity.GetCurrent().Name;
testplan.Name = release.Name + " " + template.Name + " " + testplan.UserId + " " + testplan.CreatedAt;
_provider.AddTestplan(testplan, template, release);
}
这种方法有几个问题。首先,它依赖于不确定的数据,例如DateTime。现在很难进行单元测试。马丁·福勒(Martin Fowler)对单元测试中的非确定性有着深刻的认识。它还取决于当前的WindowsIdentity
。所有这些都很难进行单元测试,因为您的方法依赖于实际实现,而不是使用抽象
因此,您必须将这些概念抽象到可以在单元测试中模拟的提供者后面。确保所有组件之间都是弱耦合的。你会发现与他们单独工作要容易得多
更新:
根据评论部分的要求,这里有一个如何提取日期时间检索的示例:
考虑以下类别:
public class WeekendTester
{
public bool IsWeekendSoon()
{
return (int)DateTime.Now.DayOfWeek > 3;
}
}
很明显,单元测试IsWeekendSoon
非常困难,因为它取决于单元测试运行的日期
因此,为了打破这种方法中的不确定性,你可以采取以下措施:
public class WeekendTester
{
private readonly Func<DateTime> _dateTimeProvider;
public WeekendTester(Func<DateTime> dateTimeProvider)
{
_dateTimeProvider = dateTimeProvider;
}
public bool IsWeekendSoon()
{
return (int)_dateTimeProvider().DayOfWeek > 3;
}
}
您可以看到,在本例中,我们可以强制该方法在单元测试中以我们希望的任何日期工作,以验证该方法的正确行为。谁说我不使用ITestPlance?除了最后两段,你说的我都知道。最后一段听起来很理论,我不习惯嘲笑。您有小代码示例吗?:-)@帕斯卡,当然,对不起,如果我的最后一段听起来像理论的话。我已经更新了我的答案,以举例说明理论并将其付诸实践。好的,谢谢你现在给我举个例子。看起来不错,但是。。。我认为这与此相关:“所有这些都很难进行单元测试,因为你在这个方法中混合了很多责任。”我应该混合哪些责任(我应该从服务中删除这3行吗?如果是,放在哪里?),你会如何解决它们?我想我不应该把这3行放在控制器中,因为控制器只处理请求/响应和视图设置等…@Pascal,对不起,可能我的措辞不正确。我实际上的意思是,您的方法依赖于具体的实现,而不是抽象。我会更新我的帖子,让这更清楚。好的,谢谢Darin,所有这些都是tobaco给我的,还有新的东西要学。它必须在接下来的几天内稳定下来。我读过的书看起来既好又有趣。有些我理解,有些会来:)
[TestMethod]
public void Weekend_Is_Still_Far_Away_From_The_28_th_Of_February_2012()
{
// arrange
Func<DateTime> providerMock = () => new DateTime(2012, 2, 28);
var sut = new WeekendTester(providerMock);
// act
var actual = sut.IsWeekendSoon();
// assert
Assert.IsFalse(actual);
}