0

Below is a method that I'm having a hard time figuring out how to test using JUnit.
This method is difficult to test because it depends on the results of other methods (e.g. getClosestDcoumentCode).

Based on my reading of JUnit, this suggests I should refactor the method. But how? And if refactoring is not necessary, how do you test a method that depends on other methods?

Thank you,

Elliott

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;
}
Elliott
  • 5,523
  • 10
  • 48
  • 87
  • 2
    Please comment with a reason when downvotting. Looks like a perfectly valid question to me. – MK. Sep 05 '11 at 02:28
  • Why are you testing a `private` class? Why is it `static` if you want to test it? There will be lots of details in the answers and reference material as to why these keywords shouldn't be in methods you are testing. – StuperUser Sep 05 '11 at 09:47
  • @MK: It could be considered too localized, although that's not even what the vote is on. Very odd. – Stefan Kendall Sep 05 '11 at 14:01

4 Answers4

7

Well, first of all, I wonder if the method really needs to be static, and what that class is doing. It looks like it might be a GOD class, or at the very least it's violating the single responsibility principle. What does getClosestCode do? If it was a class, you could inject it with a stub in your tests into the test class.

EasyMock will let you mock the method response, but I'm not sure how you mock static methods.

In general, you probably need to

  1. Extract long functions into classes
  2. Make functionality non-static
  3. Maintain the single responsibility principal
Stefan Kendall
  • 66,414
  • 68
  • 253
  • 406
5

It sounds to me like getClosestCode and getClosestDocumentCode belong to a different set of responsibilities than the findPrincipal method. So you'll want to begin by separating these into two different classes. Create an interface for each class to implement. The class that implements the findPrincipal method can then rely on the other interface as a constructor argument, like this:

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;
    }
}

Now it should be easy to create another class the implements the CodeFinder interface, either manually or using a Mocking framework. You can then control the results of each call to getClosestCode and getClosestDocumentCode, and ensure that each of these methods gets called with exactly the arguments you expect it to be called with.

StriplingWarrior
  • 151,543
  • 27
  • 246
  • 315
0

I don't read the method deeply. But if a private method needs to test, it indicates something wrong with your design. At least Kent Beck thinks so.

Community
  • 1
  • 1
卢声远 Shengyuan Lu
  • 31,208
  • 22
  • 85
  • 130
-1

There is a chapter on stub calls on JUnit Second Edition, i recommend you have a look at that if you think your existing codes are not written to test-driven development standards.

Oh Chin Boon
  • 23,028
  • 51
  • 143
  • 215