如何在Java中设计接口以方便测试?
我有一个需求,我将有两个类来处理两个存储库,比如如何在Java中设计接口以方便测试?,java,design-patterns,Java,Design Patterns,我有一个需求,我将有两个类来处理两个存储库,比如Git和Svn。这两个存储库上的操作将是相同的: 获得分支 获取提交ID 获取最后一个提交文件 等 我想我可以设计一个涵盖以下操作的界面: interface Repo{ public JSONObject getBranches() public JSONObject getCommits() . . . . } 现在类Git和Svn可以实现Repo。一切都很好 但问题来了,我们将如何测试这些接口?因为到repo的连接在各自
Git
和Svn
。这两个存储库上的操作将是相同的:
interface Repo{
public JSONObject getBranches()
public JSONObject getCommits()
. . . .
}
现在类Git
和Svn
可以实现Repo
。一切都很好
但问题来了,我们将如何测试这些接口?因为到repo的连接在各自的类Git
,Svn
(例如在其构造函数中)中处理。所以看起来像
class Git implements Repo {
public Git(String url, String username, String password){
//connect to git url
}
. . .
}
现在,就接口而言,这是一个公平的设计(就测试而言),还是我们需要将创建与repo连接的逻辑移动到其他类,比如RepoFactory
,并将它们注入方法参数中?因此,Repo
界面如下所示:
interface Repo{
public JSONObject getBranches(RepoFactory repo)
public JSONObject getCommits(RepoFactory repo)
. . . .
}
我们还可以注入RepoFactory
的模拟,以便于测试
哪个设计会更好?或者还有比这两个更好的东西?为什么需要测试接口?我认为您必须测试repo的两种实现:Git和SVN。如果您需要测试更高的逻辑,您可以使用返回模拟值的定制MockRepo实现,或者使用特殊框架(如Moq框架)设置此模拟
祝你好运 这取决于你想测试什么 假设您有一个类a,它依赖于类B,它依赖于框架类 现在,如果A是您的测试单元,那么您将创建一个模拟的B伪,并根据给定的场景监视结果,并测试A的可靠性 如果你想测试B,那么它会变得很棘手,你应该问自己一个问题。B是否有符合逻辑且值得测试的部件?如果是这样的话,它们应该被提取到不同的类中并单独测试,或者您可以用接口包装框架对象,然后它就变成了一个相同的类 示例1:B从框架连接对象读取字节流,并将其传递给第三方JSON解析器,然后将结果返回给a。实际上不需要测试B,因为它只将操作委托给(希望是)已经测试过的组件 示例2:B正在从一个框架连接对象读取一个字节流,出于效率考虑,它会自己将字节流解析为一个JSON对象,然后将结果返回给a。很明显,如果您引入一个JSON解析器,创建并测试实现,那么情况将与示例1中的情况完全相同 但是我们可以说,出于某种(愚蠢和错误的)原因,您希望B成为解析字节的组件。在这种情况下,您别无选择,只能在框架连接对象上创建一个包装接口,并模拟它以返回所需的输出。这种方法的问题是对一个组件进行了不必要的抽象,该组件将永远不会有多个实现,并且缺少对B()的明确责任 然而,您的介绍中似乎存在一个设计缺陷:我不知道对您的系统的要求,但是这个接口永远不会允许不支持JSON的存储库,我认为这是不对的,我建议用定义良好的POJO来代替它。如果您肯定JSON中的用法永远是正确的,那么无论如何您都应该这样做!但是如果您坚持,那么至少要确保返回类型是您对JSON的定义,而不是某个第三方对象 在这两种情况下,我都会使用定义良好的非耦合POJO来实现如下的单一抽象级别
interface Repo {
public List<Branch> getBranches();
public List<Commit> getCommits();
. . . .
}
接口回购{
公共列表getBranchs();
公共列表getcommittes();
. . . .
}
接口的分支和提交可以通过JSON元素轻松实现。为什么不创建一个接受
Repo
的测试方法,并简单地创建一个你想要测试的Repo
的实例?@MadProgrammer:我还没完全明白为什么不编写一个期望Repo
的测试方法(公共静态无效测试(Repo-Repo)
,那么不管你传递给它什么样的实例,测试(new Git());
??@MadProgrammer:所以你说只坚持第一种模式。对吗?对我来说,是的,这并不意味着它是对的;),但是,虽然你当然应该为测试而设计,但也不要为它牺牲API的可用性;)