如何设计接口以便在Java中轻松测试?

时间:2015-12-08 04:29:54

标签: java design-patterns

我有一个要求,我将有两个类来处理两个存储库,比如GitSvn。这两个存储库的操作将是相同的:

  1. 获取分支机构
  2. 获取提交ID
  3. 获取最后一次提交文件
  4. 我想我可以设计一个涵盖这些操作的界面:

    interface Repo{
       public JSONObject getBranches()
       public JSONObject getCommits()
       . . . . 
    }
    

    现在,班级GitSvn可以实施Repo。一切都很好。

    但问题是,我们将如何测试这些接口?因为与repo的连接是在各个类GitSvn中处理的(例如在其构造函数中)。所以它看起来像

    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的模拟以便于测试。

    哪个会更好?或者其他什么比这两个更好?

2 个答案:

答案 0 :(得分:1)

为什么需要测试界面?我认为你必须测试你的repo的两个实现:Git和SVN。如果您需要测试更高的逻辑,您可以使用返回模拟值的自定义MockRepo实现,或使用Moq框架等特殊框架设置此模拟。

祝你好运!

答案 1 :(得分:0)

这取决于你想要测试什么。

假设你有一个A类,它取决于B类,它依赖于框架类。

现在,如果A是您的待测单位,那么您创建一个模拟的B假,并根据给定的场景监视结果,并测试A的稳健性。

如果你想测试B然后它变得棘手,你应该问自己一个问题。 B是否有任何符合逻辑且值得测试的部件?如果是这样,他们应该被提取到不同的类并单独测试,或者你可以用接口包装框架对象,然后它变得和A一样。

示例1:B从框架连接对象读取字节流并将它们传递给第三方JSON解析器并将结果返回给A.实际上不需要测试B,因为它只将动作委托给(希望已经测试过组件。

示例2:B正在从框架连接对象读取字节流,并且出于效率原因将它们自身解析为JSON对象,然后将结果返回给A.很明显,如果引入JSON解析器,创建并测试实现,然后情况变得与示例1中的情况完全相同。

但是我们可以说,对于某些(愚蠢和错误)的原因,你希望B成为解析字节的组件。在这种情况下,它让你别无选择,只能在框架连接对象上创建一个包装接口并模拟它以返回所需的输出。这种方法的问题是不必要地抽象一个永远不会有多个实现的组件,并且缺乏对B(SRP)的明确责任。

然而,您的介绍中似乎存在设计缺陷:我不知道您的系统的要求,但此界面永远不会允许不支持JSON的存储库,我建议用明确定义的POJO替换它。如果你肯定JSON中的使用永远都是真的,你应该这样做!但是如果你坚持,那么至少要确保返回类型是你对JSON的定义,而不是某些第三方对象。

在这两种情况下,我都会使用定义良好的非耦合POJO进行单一抽象,如下所示。

interface Repo {
   public List<Branch> getBranches();   
   public List<Commit> getCommits();
   . . . . 
}

可以通过JSON元素轻松实现接口Branch和Commit。