1

下面是一个简单的 java 类文件,用于检查用户提供的文件是否在主目录下。当文件不在主目录下时,它会引发异常。

public class A {
  public static void main(String args[]) {
     if (new A().processArgs(args[0]) {
        throw Exception("Not under home directory");
     }
  }

  // A simple method to check if the file is at home directory
  private boolean processArgs(String s) {
    File f = new File(s);
    String userHome = System.getProperty("user.home");
    if (s.startsWith(userHome) && f.exists() && additionalLogic())
      return true;  
    else
      return false;
  }
  // Additional business Logic
  private boolean additionalBusinessLogic() {
    // Do wonderful things.
  }
}

我想编写一个简单的 Junit 测试用例来测试 java 类。测试的主要关注点是附加的业务逻辑方法。有没有办法可以绕过检查目录必须在用户主目录下的位置。

我不愿意在我的主类中添加逻辑以使其了解 Junit 类。有一个更好的方法吗?

4

6 回答 6

3

虽然 fab 的解决方案没有问题,但我决定再写一个:

public class Main {
    public static void main(String args[]) {
        // TODO: Should check args length
        Validator validator = new Validator();
        validator.validateArgs(args[0]);
    }
}

public interface Configuration {
    public String getHomeDirectory();
}

public class DefaultConfiguration implements Configuration {
    public String getHomeDirectory() {
        String home = System.getProperty("user.home");
        if (home == null) {
            throw new RuntimeException("User home directory is not set!");
        }
        return home;
    }
}

public class Validator {
  private Configuration configuration;

  public Validator() {
     this(new DefaultConfiguration());
  }

  public Validator(Configuration configuration) {
     this.configuration = configuration;
  }

  // A simple method to check if the file is at home directory
  public void validateArgs(String s) {
    File f = new File(s);
    if (!s.startsWith(configuration.getHomeDirectory()) || !f.exists() || !additionalBusinessLogic())
      throw new RuntimeException("Not under home directory!");
  }

  // Additional business Logic
  private boolean additionalBusinessLogic() {
     // TODO...
     return true;
  }
}

public class ValidatorTest {
  @Test
  public void validateValidArgsTest() {
     final String homeDirectory = ".."; // TODO
     String existingFile = homeDirectory + ".."; // TODO
     new Validator(new Configuration() {
       public String getHomeDirectory() {
          return homeDirectory;
       }
     }).validateArgs(existingFile);
  }

  @Test(expected = RuntimeException.class)
  public void validateInvalidArgsTest() {
     String existingFile = ".."; // TODO
     new Validator(new Configuration() {
       public String getHomeDirectory() {
          return "-INVALID PATH-";
       }
     }).validateArgs(existingFile);
  }
}
于 2013-02-13T21:52:27.207 回答
2

您不需要让班级知道测试以使其更具可测试性。您只需要将附加逻辑与 i/o 内容分离,这也将带来更好的设计:

public class A {
  private WonderfulThingsDoer wonderfulService;

  public void main(String args[]) {
     wonderfulService = new WonderfulThingsDoer();
     if (processArgs(args[0]) {
        throw Exception("Not under home directory");
     }
  }

  // A simple method to check if the file is at home directory
  private boolean processArgs(String s) {
    File f = new File(s);
    String userHome = System.getProperty("user.home");
    if (s.startsWith(userHome) && f.exists() && additionalBusinessLogic())
      return true;  
    else
      return false;
  }
  // Additional business Logic
  private boolean additionalBusinessLogic() {
    return wonderfulService.doWonderfulThings();
  }
}

public class WonderfulThingsDoer {
  public boolean doWonderfulThings() {
    // Do wonderful things.
    return true;
  }
}

瞧,提取了一个可测试的单元。

于 2013-02-13T21:24:07.147 回答
1

不要硬编码“user.home”

创建一个您在单元代码中更改的字段主目录,以指向测试目录:

public class A {

      private static String homeDir;
      protected static void setHomeDir(String home) {
        this.homeDir = home;
      }    

      public static void main(String args[]) {
         if (homeDir == null) {
              homeDir = System.getProperty("user.home");
         }
         A a = new A();
         if (a.processArgs(args[0]) {
            throw new InvalidArgumentException("Not under home directory");
         }
      }

      // A simple method to check if the file is at home directory
      protected boolean processArgs(String s) {
        File f = new File(s);

        if (s.startsWith(A.homeDir) && f.exists() && additionalLogic())
          return true;  
        else
          return false;
      }
      // Additional business Logic
      private boolean additionalBusinessLogic() {
        // Do wonderful things.
      }
    }

现在在单元测试中,将 homeDir 设置为您的测试目录

public void testMainHomeExisting() {
    A a = new A;
    String home = "./testdata/";
    A.setHomeDir(home);
    String[] args = new String[]{home}; // hope this compiles otherwise fix it
    // no assert needed here, if test fails, an Exception is thrown
    A.main(args);
}

现在是不存在的家庭测试用例

public void testMainHomeNotExisting() {
    A a = new A;
    String home = "./notExistingFooBarFooFoo/";
    A.setHomeDir(home);
    String[] args = new String[]{home}; // hope this compiles otherwise fix it
    // no assert needed here, if test fails, an Exception is thrown
    try {
       A.main(args);
       // if code works the next line should not be reached:
       fail("Expected IllegalArgumentException");
    } catch (IllegalArgumentException ex) {
       // as expected got IllegalArgumentException
    }
}
于 2013-02-13T22:05:51.310 回答
0

Just make a Test for the core business method additionalBusinessLogic only. You don't need to call main.

于 2013-02-13T21:18:59.700 回答
0

I see no reason to call main.

When you're writing a unit test, you want them to be modular enough to call without relying too much on external methods - and what you can't call you can mock, using something like EasyMock, PowerMock or Mockito.

于 2013-02-13T21:19:03.010 回答
0

我会更改您要测试的方法...

  1. 删除访问修饰符
  2. 传入File您需要能够执行逻辑的变量

boolean additionalBusinessLogic(File f)

这将允许同一包中的测试类调用该方法。如果您将其保留为私有,则其他类将无法调用它。

一旦你可以调用你想要测试的方法,测试类就很容易了......

public class MyClassTest {
    @Test
    public void additionalBusinessLogic_shouldFoo_whenSomeCondition() {
        // setup
        A a = new A();
        File mockFile = mock(File.class);
        // other setup stuff

        // execute
        boolean result = a.additionalBusinessLogic(mockFile);

        // assert
        // verify whatever you need to
    }
}

对于一个好的模拟框架,我建议Mockito

于 2013-02-13T21:28:52.260 回答