如何重构方法以使其更容易测试

时间:2011-09-05 02:09:09

标签: java testing refactoring junit

下面是一个方法,我很难弄清楚如何使用JUnit进行测试 这种方法很难测试,因为它取决于其他方法的结果(例如getClosestDcoumentCode)。

基于我对JUnit的阅读,这表明我应该重构该方法。但是怎么样?如果不需要重构,你如何测试依赖于其他方法的方法?

谢谢,

埃利奥特

private static String findPrincipal(List<DocumentKey> documentkeys_) {
    Hashtable<String, Integer> codecounts = new Hashtable<String, Integer>();
    for (DocumentKey document : documentkeys_) {
        int x = 0;
        String closestCode = getClosestDocumentCode(document.candidates);
        if (closestCode == null) continue;
        int thecount = 0;
        if (codecounts.containsKey(closestCode))
            thecount = codecounts.get(closestCode);
        if (document.hasKey)
            thecount += 2;
        else
            thecount++;
        codecounts.put(closestCode, new Integer(thecount));
        x++;

    }
    String closestCode = getClosestCode(codecounts);
    return closestCode;
}

4 个答案:

答案 0 :(得分:7)

嗯,首先,我想知道该方法是否真的需要是静态的,以及该类正在做什么。看起来它可能是一个GOD类,或者至少它违反了单一责任原则。 getClosestCode有什么作用?如果它是一个类,你可以在测试中将它与一个存根一起注入到测试类中。

EasyMock会让你模拟方法响应,但我不确定你是如何模拟静态方法的。

一般来说,你可能需要

  1. 将长函数提取到类
  2. 使功能非静态
  3. 维持单一责任主体

答案 1 :(得分:5)

听起来像getClosestCodegetClosestDocumentCode属于职责不同于findPrincipal方法。所以你要首先将它们分成两个不同的类。为每个要创建的类创建一个接口。然后,实现findPrincipal方法的类可以依赖于另一个接口作为构造函数参数,如下所示:

public class PrincipalFinderImpl implements PrincipalFinder
{
    private CodeFinder codeFinder;
    public PrincipalFinderImpl(CodeFinder codeFinder) {
        this.codeFinder = codeFinder;
    }
    public String findPrincipal(List<DocumentKey> documentkeys_) {
        Hashtable<String, Integer> codecounts = new Hashtable<String, Integer>();
        for (DocumentKey document : documentkeys_) {
            int x = 0;
            String closestCode = codeFinder.getClosestDocumentCode(document.candidates);
            if (closestCode == null) continue;
            int thecount = 0;
            if (codecounts.containsKey(closestCode))
                thecount = codecounts.get(closestCode);
            if (document.hasKey)
                thecount += 2;
            else
                thecount++;
            codecounts.put(closestCode, new Integer(thecount));
            x++;

        }
        String closestCode = codeFinder.getClosestCode(codecounts);
        return closestCode;
    }
}

现在应该很容易创建另一个实现CodeFinder接口的类,手动或使用Mocking框架。然后,您可以控制每次调用getClosestCodegetClosestDocumentCode的结果,并确保使用您希望调用的参数调用这些方法中的每一个。

答案 2 :(得分:0)

我没有深入阅读这个方法。但是如果私有方法需要测试,则表明您的设计存在问题。至少Kent Beck thinks so

答案 3 :(得分:-1)

JUnit Second Edition上有关于存根调用的章节,如果您认为现有代码不是针对测试驱动的开发标准,我建议您查看一下。