Language agnostic 开发与TDD的接口
我是TDD的忠实粉丝,这些天我的大部分开发都使用它。不过,我经常遇到的一种情况是,我从未找到我认为“好”的答案,类似于下面的(人为的)例子 假设我有这样一个接口(用Java编写,但实际上,这适用于任何OO语言): 现在,假设我想创建这个接口的三个实现。让我们称它们为Language agnostic 开发与TDD的接口,language-agnostic,tdd,polymorphism,Language Agnostic,Tdd,Polymorphism,我是TDD的忠实粉丝,这些天我的大部分开发都使用它。不过,我经常遇到的一种情况是,我从未找到我认为“好”的答案,类似于下面的(人为的)例子 假设我有这样一个接口(用Java编写,但实际上,这适用于任何OO语言): 现在,假设我想创建这个接口的三个实现。让我们称它们为DijkstraPathFinder,DepthFirstPathFinder,和AStarPathFinder 问题是,我如何使用TDD开发这三个实现?它们的公共接口将是相同的,并且,据推测,我将为每一个编写相同的测试,因为getS
DijkstraPathFinder
,DepthFirstPathFinder
,和AStarPathFinder
问题是,我如何使用TDD开发这三个实现?它们的公共接口将是相同的,并且,据推测,我将为每一个编写相同的测试,因为getShortestPath()和getShortestPathLength()的结果在所有三个实现中应该是一致的
我的选择似乎是:
PathFinder
编写一组测试。然后编写另外两个实现“盲”并确保它们通过PathFinder
测试。这似乎不对,因为我没有使用TDD来开发第二个和第二个实现类这似乎是一种相当常见的情况,尤其是在实现策略模式时,当然,实现之间的差异可能不仅仅是时间复杂性。其他人如何处理这种情况?是否有针对我不知道的接口进行测试优先开发的模式?您编写接口测试来练习接口,并为实际实现编写更详细的测试。讨论了单元测试应该为该接口形成一种“契约”规范这一事实。也许当Spec出来时,会有一种语言支持的方法来实现这一点 在这个特殊的情况下,这是一个严格的策略实现,接口测试就足够了。在其他情况下,如果接口是实现功能的一个子集,则需要对接口和实现进行测试。例如,考虑一个实现了3个接口的类
编辑:这很有用,因此当您添加接口的另一个实现时,您已经有了验证类是否正确实现接口约定的测试。这可以适用于像ISortingStrategy这样特定的东西,也可以适用于像IDisposable这样范围广泛的东西。例如,针对接口编写测试并在每个实现中重用它们并没有什么错-
public class TestPathFinder : TestClass
{
public IPathFinder _pathFinder;
public IGraphNode _startNode;
public IGraphNode _goalNode;
public TestPathFinder() : this(null,null,null) { }
public TestPathFinder(IPathFinder ipf,
IGraphNode start, IGraphNode goal) : base()
{
_pathFinder = ipf;
_startNode = start;
_goalNode = goal;
}
}
TestPathFinder tpfDijkstra = new TestPathFinder(
new DijkstraPathFinder(), n1, nN);
tpfDijkstra.RunTests();
//etc. - factory optional
我认为这是最省力的解决方案,非常符合敏捷/TDD原则。我不介意将测试代码作为模板重用,用于具有类似功能的新测试。根据测试中的特定类,您可能必须使用不同的模拟对象和期望对它们进行返工。至少您必须重构它们以使用新的实现。不过,我会遵循TDD方法,进行一次测试,为新类重新编写测试,然后只编写代码以通过该测试。不过,这可能需要更多的规范,因为您已经有了一个实现,并且无疑会受到您已经编写的代码的影响。我对选项1没有问题,请记住,重构是TDD的一部分,通常在重构阶段,您会转向一种设计模式,比如策略,所以我不会因为编写新的测试而感到不安
如果您想测试每个探索者IMPL的具体实现细节,您可以考虑通过模拟的图形节点,它能够帮助确定实现的Dijkstra或DethTraseNess等。(也许这些模拟图形节点可以记录它们是如何被遍历的,或者以某种方式测量性能。)也许这是测试过度,但如果您知道您的系统出于某种原因需要这三种不同的策略,有测试来证明为什么可能是好的,否则为什么不选择一个实现并扔掉其他的呢
这似乎不对,因为我 不使用TDD开发第二个 两个实现类 当然可以 首先,注释掉除一个测试之外的所有测试。当您通过测试时,重构或取消注释另一个测试联合特遣部队我仍然有问题。我采用的方法是测试驱动两个相同的类,然后重构到一个公共接口。当添加第三个类时,我剪切粘贴测试,并通过向类添加接口使每个测试依次编译并变为绿色。如果剪切粘贴出错,这很容易出错,但这不是我的问题。现在,我可以使用测试从一个类向接口添加功能,但该功能在其他类中没有支持它的测试。我得记得把测验抄过来。这似乎不对?将我的评论拉到一个新问题中:
public class TestPathFinder : TestClass
{
public IPathFinder _pathFinder;
public IGraphNode _startNode;
public IGraphNode _goalNode;
public TestPathFinder() : this(null,null,null) { }
public TestPathFinder(IPathFinder ipf,
IGraphNode start, IGraphNode goal) : base()
{
_pathFinder = ipf;
_startNode = start;
_goalNode = goal;
}
}
TestPathFinder tpfDijkstra = new TestPathFinder(
new DijkstraPathFinder(), n1, nN);
tpfDijkstra.RunTests();
//etc. - factory optional