我们最近采用了用于验证域对象的规范模式,现在想要引入域对象的单元测试以提高代码质量。
我发现的一个问题是如何最好地对下面示例中显示的验证功能进行单元测试。规范命中数据库所以我希望能够模拟它,但因为它是在线实例化我不能这样做。我可以处理接口,但这会增加代码的复杂性,因为我们可能有很多规范,我们最终会有很多接口(记住我们正在引入单元测试,并且不想给任何人找借口来拍摄它向下)。
鉴于这种情况,我们如何才能最好地解决单元测试域对象中规范模式的问题?
...
public void Validate()
{
if(DuplicateUsername())
{ throw new ValidationException(); }
}
public bool DuplicateUsername()
{
var spec = new DuplicateUsernameSpecification();
return spec.IsSatisfiedBy(this);
}
答案 0 :(得分:5)
通过制作核心方法virtual
,可以更加温和地将 Seams 引入应用程序。这意味着您可以使用提取和覆盖技术进行单元测试。
在绿地开发中,我发现这种技术不是最理想的,因为有更好的替代方案,但它是将可测试性改进现有代码的好方法。
例如,您写道您的规范命中数据库。在该实现中,您可以将规范的那一部分提取到Factory Method,然后您可以在单元测试中覆盖。
通常,本书Working Effectively with Legacy Code为如何使代码可测试提供了许多有价值的指导。
答案 1 :(得分:2)
如果您不想对工厂进行构造函数注入,并使规范可以模拟......您是否考虑过TypeMock?处理这类事情非常有用。你可以告诉它模拟要创建的X类型的下一个对象,它可以模拟任何东西,不需要虚拟等。
答案 2 :(得分:1)
您可以将getDuplicateUsernameSpecification()
提取到自己的公共方法中,然后将其子类化并覆盖测试。
答案 3 :(得分:1)
如果您使用IoC,那么您可以解析DuplicateUsernameSpecification并在测试模型中解析最后一个
编辑:想法是用工厂方法替换直接构造函数调用。像这样:
public bool DuplicateUsername()
{
var spec = MyIocContainer.Resolve<DuplicateUsernameSpecification>();
return spec.IsSatisfiedBy(this);
}